通信对象使用命名管道WCF服务时出现故障

时间:2012-02-14 09:34:13

标签: c# .net wcf named-pipes

我们的.NET应用程序使用2个AppDomains。辅助域需要访问在主应用程序域中创建的Logger对象。

此记录器通过具有命名管道绑定的WCF服务公开。

这就是我为这项服务创建“客户”的方式:

        private void InitLogger()
        {    
            if (loggerProxy != null)
            {
                Logger.Instance.onLogEvent -= loggerProxy.Log;
            }

            // Connect to the logger proxy.
            var ep = new EndpointAddress("net.pipe://localhost/app/log");
            var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);

            //Logger.Debug("Creating proxy to Logger object.");
            var channelFactory = new ChannelFactory<ILogProvider>(binding, ep);

            loggerProxy = channelFactory.CreateChannel();
            channelFactory.Faulted += (sender, args) => InitLogger();
            channelFactory.Closed += (sender, args) => InitLogger();

            Logger.Instance.onLogEvent += loggerProxy.Log;
        }

最近我们得到随机的CommunicationObjectFaultedException - 我想这是因为频道超时或由于某些其他原因导致我失踪。

这就是我添加已关闭 Faulted 事件的处理的原因,这些事件似乎无法正常工作(可能我没有正确使用它们)。< / p>

编辑:这些事件在建议的Factory对象上,因此这解释了为什么它们没有被提升。

我的问题是 - 如何避免这些错误?

我们的情况是,我们需要在整个应用程序的生命周期内始终保持此通道处于打开状态,并且始终需要访问此Logger服务,并且在任何情况下都不应超时。

是否有处理此类情况的安全做法?

2 个答案:

答案 0 :(得分:6)

您的代码当前正在处理ChannelFactory引发的Closed和Faulted事件,但是您需要担心的是Channel本身的状态。

ChannelFactory是一个人工制品,它将WCF服务合同的转换封装到通道运行时的实例中:一旦您成功创建了通道(loggerProxy),ChannelFactory的关闭就不会通过频道影响通信 - 您正在侦听的事件与您的问题无关。

Channel 到Closed或Faulted的状态转换将不会被注意到此代码,结果它们将在Logger.Instance中显示为调用loggerProxy.Log时抛出的异常,并且您尝试记录的事件将丢失。

不应直接将loggerProxy.Log注册为事件处理程序,而应考虑注册实现异常处理程序的包装函数,并围绕对loggerProxy.Log的调用重试循环。应在异常处理程序中关闭现有通道(如果失败,中止),以确保它已正确处置。重试循环应该重新初始化频道并再次尝试呼叫。

答案 1 :(得分:1)

我将评论两件事(i)超时和(ii)捕捉Faulted事件。

首先是超时。默认情况下,如果通道在默认时间段(大约10分钟)内没有通信,则进入故障状态。您可以使用重复事件频繁地戳频道,也可以将超时重置为较大的事件。我按如下方式做后者:

    NetNamedPipeBinding binding = new NetNamedPipeBinding();

    // Have to set the receive timeout to be big on BOTH SIDES of the pipe, otherwise it gets faulted and can't be used.
    binding.ReceiveTimeout = TimeSpan.MaxValue;

    DuplexChannelFactory<INodeServiceAPI> pipeFactory =
       new DuplexChannelFactory<INodeServiceAPI>(
          myCallbacks,
          binding,
          new EndpointAddress(
             "net.pipe://localhost/P2PSN.Node.Service.Pipe"));

myCallbacks是一个类的实例,它处理双工管道中的回调,而INodeServiceAPI是描述我的API的接口。

其次,你在工厂的事件是正确的,不会被解雇。您可以在频道上捕捉事件。我使用以下代码。

    proxy = pipeFactory.CreateChannel();
    if (proxy is IClientChannel)
    {
        (proxy as IClientChannel).Faulted += new EventHandler(this.proxy_Faulted);
    }

不愉快,但是我从其他地方的StackOverflow中选择了一些有用的东西。您必须包含System.ServiceModel以获取IClientChannel接口。

HTH。