繁体   English   中英

对WCF客户端的异步调用会阻止后续同步调用

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM