[英]Async call to WCF client blocks subsequent synchronous calls
我在客户端上调用生成的Async方法时遇到WCF问题...如果我等待异步方法,然后在同一客户端上调用非异步方法,则阻塞方法永远不会返回。
这是一个简单的问题再现:
[ServiceContract]
public interface IService1
{
[OperationContract] void DoWork();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service1 : IService1
{
public void DoWork()
{
}
}
这里没什么复杂的。 一个简单的WCF服务(同步实现),公开单个方法。
class Program
{
static void Main(string[] args)
{
var svc = new ServiceHost(typeof(Service1));
svc.Open();
RunClient().Wait(); // This is a console app. There is no SynchronizationContext to confuse things.
svc.Close();
}
static async Task RunClient()
{
var client = new ServiceReference1.Service1Client();
client.DoWork();
Console.WriteLine("Work Done");
await client.DoWorkAsync();
Console.WriteLine("Async Work Done");
Console.WriteLine("About to block until operation timeout...");
client.DoWork();
Console.WriteLine("You'll never get here.");
}
}
请注意,这不是通常情况下某人阻止消息抽取线程或忘记调用ConfigureAwait(false)
。 这是一个控制台应用程序,添加ConfigureAwait
对行为没有影响。
奇怪的是,帮助是做什么的:
await Task.Delay(1); // Magical healing worker thread context switch
在再次调用同步WCF方法之前。 因此,看起来WCF在从异步方法调用恢复之后会以某种方式留下一些线程局部上下文,然后将其清除。
知道是什么原因引起的吗? 来自死锁/非死锁情况的调用堆栈揭示了WCF客户端操作中的一些差异:
好堆栈:
System.ServiceModel.dll!System.ServiceModel.Channels.TransportDuplexSessionChannel.Receive(System.TimeSpan timeout)
System.ServiceModel.dll!System.ServiceModel.Channels.TransportDuplexSessionChannel.TryReceive(System.TimeSpan timeout, out System.ServiceModel.Channels.Message message) System.ServiceModel.dll!System.ServiceModel.Dispatcher.DuplexChannelBinder.Request(System.ServiceModel.Channels.Message message, System.TimeSpan timeout)
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannel.Call(string action, bool oneway, System.ServiceModel.Dispatcher.ProxyOperationRuntime operation, object[] ins, object[] outs, System.TimeSpan timeout)
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(System.Runtime.Remoting.Messaging.IMethodCallMessage methodCall, System.ServiceModel.Dispatcher.ProxyOperationRuntime operation)
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannelProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage message)
mscorlib.dll!System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(ref System.Runtime.Remoting.Proxies.MessageData msgData, int type)
坏堆栈:
mscorlib.dll!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle waitableSafeHandle, long millisecondsTimeout, bool hasThreadAffinity, bool exitContext)
mscorlib.dll!System.Threading.WaitHandle.WaitOne(System.TimeSpan timeout, bool exitContext)
System.ServiceModel.Internals.dll!System.Runtime.TimeoutHelper.WaitOne(System.Threading.WaitHandle waitHandle, System.TimeSpan timeout)
System.ServiceModel.dll!System.ServiceModel.Dispatcher.DuplexChannelBinder.SyncDuplexRequest.WaitForReply(System.TimeSpan timeout)
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannel.Call(string action, bool oneway, System.ServiceModel.Dispatcher.ProxyOperationRuntime operation, object[] ins, object[] outs, System.TimeSpan timeout)
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(System.Runtime.Remoting.Messaging.IMethodCallMessage methodCall, System.ServiceModel.Dispatcher.ProxyOperationRuntime operation)
System.ServiceModel.dll!System.ServiceModel.Channels.ServiceChannelProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage message)
mscorlib.dll!System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(ref System.Runtime.Remoting.Proxies.MessageData msgData, int type)
在异步调用完成后,似乎DuplexChannelBinder
WCF中的某个DuplexChannelBinder
假定有另一个线程正在读取来自通道的消息。
有什么想法吗? 显然,我对将修复Task.Delay
语句添加到我的代码中的想法并不感到兴奋......
干杯,马克
当使用相同的客户端调用多个操作时,我遇到了类似的问题。 使用同一个对象不能同时调用多个方法,它看起来像是在wcf方法调用中实现的一些锁定。
所以直到1次调用未完成,你才能再次使用同一个对象调用wcf服务。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.