CommunicationObjectFaults при использовании службы WCF NamedPipe - PullRequest
4 голосов
/ 14 февраля 2012

Наше приложение .NET использует 2 домена приложений. Вторичный домен нуждается в доступе к объекту 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;
        }

Недавно мы получаем случайное исключение CommunicationObjectFaptedException - я полагаю, это происходит с момента истечения срока действия канала или по какой-то другой причине, по которой я пропускаю.

По этой причине я добавил обработку событий Closed и Failed , которые, кажется, не работают должным образом (возможно, я не использовал их надлежащим образом).

РЕДАКТИРОВАТЬ: Эти события находятся на объекте Factory, как это было предложено, поэтому это объясняет, почему они не вызываются.

Мой вопрос - как мне избежать этих ошибок?

Наш сценарий заключается в том, что нам нужно постоянно держать этот канал открытым на протяжении всего жизненного цикла приложения, а доступ к этой службе Logger необходим всегда и не должен прерываться ни при каких обстоятельствах.

Существует ли какая-либо безопасная практика обращения с подобными ситуациями?

Ответы [ 2 ]

6 голосов
/ 17 февраля 2012

Ваш код в настоящее время обрабатывает закрытые и ошибочные события, вызванные ChannelFactory, но вам нужно беспокоиться о состоянии самого канала.

ChannelFactory - это артефакт, который инкапсулирует перевод WCFконтракт на обслуживание для экземпляра среды выполнения канала: после успешного создания канала (loggerProxy) закрытие ChannelFactory не повлияет на связь через канал - события, которые вы слушаете, не имеют отношения к вашей проблеме.

Переходы состояния Канала в Закрытый или Неисправный будут незамеченными для этого кода, в результате чего они будут отображаться в Logger.Instance как исключения, выдаваемые при вызове loggerProxy.Log,и событие, которое вы пытаетесь записать, будет потеряно.

Вместо регистрации loggerProxy.Log непосредственно в качестве обработчика событий вам следует рассмотреть возможность регистрации функции-оболочки, реализующей обработчик исключений, и повторного цикла вокруг вызова loggerProxy.Log.Существующий канал должен быть закрыт (или, если это не удалось, прерван) в обработчике исключений, чтобы обеспечить его правильное удаление.Цикл повторной попытки должен повторно инициализировать канал и повторить попытку вызова.

1 голос
/ 11 апреля 2012

Я прокомментирую две вещи: (i) время ожидания и (ii) перехват событий Failed.

Во-первых, время ожидания.По умолчанию каналы переходят в состояние отказа, если они не имели связи в течение периода времени по умолчанию (около 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.

...