我在客户端上调用生成的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中的某个位置假定在异步调用完成后,另一个线程正在读取来自通道的消息。
有什么想法?显然,我对将Task.Delay
语句添加到我的代码中的想法并不感到激动......
干杯, 标记
答案 0 :(得分:1)
当使用相同的客户端调用多个操作时,我遇到了类似的问题。 使用相同的对象不能同时调用多个方法,它看起来像是在wcf方法调用中实现的一些锁定。
所以直到1次调用未完成,你才能再次使用同一个对象调用wcf服务。