我对WCF服务有一个奇怪的问题,我无法解决。 当我在我的服务上调用特定方法时,它只是在绑定超时之前不会返回到客户端,尽管它已经在服务器上返回并且已经向客户端发送了返回消息。
我在客户端使用ChannelFactory<T>
,并且共享接口定义如下:
[ServiceContract]
interface IService {
[OperationContract] bool Upload(Guid id, string name, byte[] data);
[OperationContract] bool Unlock(Guid id);
}
[ServiceContract(Name = "IService")]
interface IServiceAsync : IService {
[OperationContract] Task<bool> UploadAsync(Guid id, string name, byte[] data);
[OperationContract] Task<bool> UnlockAsync(Guid id);
}
IService
接口由服务器类实现,IServiceAsync
接口仅在客户端上使用(并自动工作)。
服务器使用ServiceHost
在独立控制台应用程序中实现,服务器类如下所示:
[ServiceBehavior(InstanceContextMode = Single, ConcurrencyMode = Multiple)]
static class Server : IService {
public bool Upload(Guid id, string name, byte[] data) { ... }
public bool Unlock(Guid id) { ... }
}
在客户端,我使用ChannelFactory<T>
创建一个频道,如下所示:
static IServiceAsync GetService() {
EndpointAddress endpoint = new EndpointAddress(/* some Uri */);
NetTcpBinding binding = /* NetTcpBinding without security */;
ChannelFactory<IServiceAsync> factory =
new ChannelFactory<IServiceAsync>(binding, endpoint);
factory.Open();
IServiceAsync proxy = factory.CreateChannel();
((IServiceChannel)proxy).Open();
return proxy;
}
在我的场景中,我然后将一些文件上传到服务器,这个操作可以随时由用户取消。上传代码如下所示:
static async void UseService(IServiceAsync proxy) {
try {
byte[] buffer;
do {
cancellationToken.ThrowIfCancellationRequested();
buffer = GetBytes();
bool uploaded = await proxy.UploadAsync(id, name, buffer);
} while(buffer.Length > 0);
((IClientChannel)proxy).Close();
}
catch (Exception ex) {
try {
proxy.Unlock(id);
}
catch {
// Connection may have failed
}
throw;
}
}
现在上传完成后一切正常,但是当上传被取消,cancellationToken.ThrowIfCancellationRequested()
引发异常时,我想解锁服务器。
所以我调用proxy.Unlock(id)
,它在服务器上被调用,返回那里(通过在服务器上return true;
之前写入控制台确认),但是在绑定超时之前不会在客户端返回
我查看了一次网络流量并确认实际上有一条返回消息发送给客户端。 (我实际上并不知道proxy.Unlock(id)
是返回还是抛出CommunicationException
,我怀疑是第二个。)
TL; DR:虽然WCF方法已在服务器端返回,但客户端没有返回WCF方法,其他方法工作正常。
所以,如果你仍然在那个文本墙之后仍然在这里:这里有什么问题? 我该如何调试或解决这个问题? 如果您需要更多信息,请告诉我。
感谢Daniel的评论,我做了一些跟踪,并成功地重现了这个问题。
在等待异步WCF方法时使用ConfigureAwait(false)
时会出现问题,抛出异常,并且在下次调用WCF方法之前没有上下文切换。我在GitHub上传了一个小test project。
这可能是WCF代理中自动实现的异步方法中的错误吗?