WCF 命名管道在 WinApp 中超时,但在 ConsoleApp 中没有?

Posted

技术标签:

【中文标题】WCF 命名管道在 WinApp 中超时,但在 ConsoleApp 中没有?【英文标题】:WCF Named Pipes timeout in a WinApp, but not in a ConsoleApp? 【发布时间】:2017-03-25 08:03:16 【问题描述】:

关于Async two-way communication with Windows Named Pipes (.Net) 似乎已死(即线程):/

我想知道为什么下面的代码可以在 ConsoleApplications 中完美运行,但是当我对 WindowsApplications 执行完全相同的操作时,调用“Console.WriteLine(proxy.ProcessData());”时客户端会出现超时。奇怪的是,服务器方法“ProcessData”被调用,没有任何异常,但在默认1分钟后我仍然超时?!

我该如何解决这个问题...ConsoleApp 和 WinApp 之间到底有什么区别(除了显而易见的),这就是这样的东西不起作用的原因?

使用 WCF,您可以使用双工命名管道

// Create a contract that can be used as a callback
    public interface IMyCallbackService
    
        [OperationContract(IsOneWay = true)]
        void NotifyClient();
    

    // Define your service contract and specify the callback contract
    [ServiceContract(CallbackContract = typeof(IMyCallbackService))]
    public interface ISimpleService
    
        [OperationContract]
        string ProcessData();
    

实施服务

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
    public class SimpleService : ISimpleService
    
        public string ProcessData()
        
            // Get a handle to the call back channel
            var callback = OperationContext.Current.GetCallbackChannel<IMyCallbackService>();

            callback.NotifyClient();
            return DateTime.Now.ToString();
        
    

托管服务

class Server

    static void Main(string[] args)
    
        // Create a service host with an named pipe endpoint
        using (var host = new ServiceHost(typeof(SimpleService), new Uri("net.pipe://localhost")))
        
            host.AddServiceEndpoint(typeof(ISimpleService), new NetNamedPipeBinding(), "SimpleService");
            host.Open();

            Console.WriteLine("Simple Service Running...");
            Console.ReadLine();

            host.Close();
        
    

创建客户端应用程序,在本例中,客户端类实现回调合约。

class Client : IMyCallbackService

    static void Main(string[] args)
    
        new Client().Run();
    

    public void Run()
    
        // Consume the service
        var factory = new DuplexChannelFactory<ISimpleService>(new InstanceContext(this), new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/SimpleService"));
        var proxy = factory.CreateChannel();

        Console.WriteLine(proxy.ProcessData());
    

    public void NotifyClient()
    
        Console.WriteLine("Notification from Server");
    

【问题讨论】:

【参考方案1】:

原因是同步上下文在调用回调时很重要。 你从ProcessData内部调用回调方法。

如果控制台应用程序没有设置任何同步上下文,这意味着当ProcessData 返回时,当主线程正在等待时,WCF 将在单独的线程中调用客户端上的回调方法。如果您在控制台消息中记录线程 ID,您可以看到这一点。

如果是 Windows 应用程序主线程设置同步上下文(WinForms 或 WPF)。如果您从主线程调用您的服务,那么 WCF 将尝试在同一同步上下文中调用您的回调方法。但是这个同步上下文的唯一线程正忙于等待ProcessData返回。

您可以通过两种方式解决这个问题: 1.设置UseSynchronizationContext=false为您的回拨。 2. 从应用程序的后台线程调用您的服务 - 然后将在其他线程池线程上调用回调。

请注意,使用这两个选项,您无法直接从这些后台线程访问 UI 元素 - 您需要编组对 UI 线程的调用。

【讨论】:

以上是关于WCF 命名管道在 WinApp 中超时,但在 ConsoleApp 中没有?的主要内容,如果未能解决你的问题,请参考以下文章

当 2 个进程尝试同时在不同管道上相互通信时,使用命名管道的 WCF IPC 会崩溃

WCF 服务命名管道故障

创建命名管道 (WCF) 所需的最低操作系统权限

WCF 命名管道 IO 异常 - 管道已结束。 (109, 0x6d)

WCF命名管道另一个端点错误但没有其他端点?

WCF 命名管道最小示例