Лучшие практики с WCF ChannelFactory и временем ожидания соединения - PullRequest
6 голосов
/ 16 декабря 2011

Я работаю над приложением winform, которое получит доступ к службе WCF, размещенной в качестве службы Windows.Я использую ChannelFactory вместо ссылки на сервис.Я успешно подключился и позвонил в службу WCF.Проблема в том, что я оставляю приложение бездействующим в течение 20 минут, а затем пытаюсь сделать еще один вызов.Я получаю следующую ошибку:

"Соединение с сокетом было прервано. Это может быть вызвано ошибкой обработки вашего сообщения или превышением тайм-аута приема удаленным хостом, или проблемой основного сетевого ресурса. Тайм-аут локального сокетабыло '00: 00: 59.9489970 '. "

Я ищу лучшие практики по управлению соединением.В настоящее время я создал функцию с именем PrepareWCFConnection (см. Ниже), которая проверяет состояние канала и ChannelFactory.Я вызываю этот метод перед тем, как сделать какие-либо вызовы службам WCF.Есть ли лучший способ справиться с этим?

     public bool PrepareWCFConnection()
    {
        if ((channelFactory == null) || 
            (channelFactory.State == CommunicationState.Faulted) ||
            (channelFactory.State != CommunicationState.Opened))
        {
            channelFactory = new ChannelFactory<IService1>(new NetTcpBinding(), endpointAddress);
        }


        if ((proxy == null) ||
            (((IClientChannel)proxy).State == CommunicationState.Faulted) ||
            (((IClientChannel)proxy).State != CommunicationState.Opened))
        {
            proxy = channelFactory.CreateChannel(endpointAddress);
            ((IClientChannel)proxy).Open();
        }

        return true;
    }

Ответы [ 3 ]

5 голосов
/ 12 февраля 2013

Если вы хотите повторно использовать существующий канал, вам нужно поддерживать канал активным, пропуская службу каждые 9 минут. Я думаю, что тайм-аут приема по умолчанию составляет 10 минут, поэтому канал будет отключен, если он будет простаивать после этого.Или вы можете использовать надежные сеансы для поддержания каналов в рабочем состоянии.

Если вам не требуется обратный вызов на том же канале, лучше закрыть канал после завершения и заново создать новый канал для каждой операции службыСоздание каналов не дорого. Вы можете кэшировать фабрику каналов, но создавать каналы для каждого вызова.

2 голосов
/ 08 февраля 2016

Я знаю, что этот вопрос довольно старый, но я вижу, что на него действительно не было ответа.Есть два тайм-аута (ну, только 1, если вы не используете надежный обмен сообщениями), которые вам следует учитывать, когда речь идет о тайм-ауте каналов.На стороне службы у вас есть «ReceiveTimeout», которое запускается, если в течение периода ожидания не было получено ни одного сообщения приложения.По умолчанию этот тайм-аут составляет 10 минут.

Существует также «InactivityTimeout», который используется только в том случае, если включен «ReliableSession».Этот тайм-аут - это максимальная продолжительность, в течение которой канал позволяет другой взаимодействующей стороне не отправлять никаких сообщений до выхода из строя канала.

Чтобы увеличить время жизни вашего канала, я рекомендую включить «ReliableSession», а затем установить оба «ReceiveTimeout "&" InactivityTimeout "для более высокого значения.ReliableSession поддерживает канал живым, отправляя ILM (сообщения уровня инфраструктуры), такие как keep-alive (сообщения также отправляются).Если сообщение keep-alive или ALM (сообщение уровня приложения) не получено до истечения срока действия «InactivityTimeout», канал выйдет из строя.

Более того, если ALM (сообщение уровня приложения) не было получено до «ReceiveTimeout»«истекает, когда канал выйдет из строя.

Итак, рекомендуется либо увеличить оба тайм-аута до одного и того же значения, либо установить« ReceiveTimeout »на более высокое значение, чем« InactivityTimeout ».

AПримечание: установка «ReceiveTimeout» не будет иметь никакого эффекта при установке на стороне клиента, это только тайм-аут на стороне службы.Но при использовании ReliableSession на стороне службы клиент также должен реализовать это следующим образом:

NetTcpBinding binding = new NetTcpBinding
        {
            ReliableSession = { Enabled = true },             
            SendTimeout = TimeSpan.FromMinutes( 1 )
        };

        binding.ReliableSession.InactivityTimeout = TimeSpan.Parse( "24.20:31:23.6470000" );

И app.config на стороне службы будет выглядеть примерно так:

<bindings>
    <netTcpBinding>
      <binding name="netTestTcpBinding"
               receiveTimeout="24.20:31:23.6470000">
        <reliableSession inactivityTimeout="24.20:31:23.6470000"
                         enabled="true" />
      </binding>
    </netTcpBinding>
  </bindings>
<services>
  <service>
    <endpoint address="IServiceContract"
              binding="netTcpBinding"
              bindingConfiguration="netTestTcpBinding"
              name="serviceContractTcpBinding"/>
    <host>
        <baseAddresses>
             <add baseAddress="net.tcp://localhost:12001/" />
        </baseAddresses>
     </host>
    </service>                   
</services>
0 голосов
/ 08 июня 2017

Одно довольно прямолинейное решение для повторного использования вашего канала, без опроса или для чего-то интересного - просто позаботьтесь о последнем вызове на ваш канал и проверьте wcfC.Binding.ReceiveTimeout, чтобы восстановить его при необходимости, например: 1001 *

    TimeSpan timeSpan = DateTime.Now - LastCallTime;
    if (timeSpan.TotalSeconds > wcfC.Binding.ReceiveTimeout.TotalSeconds || wcfC.State != CommunicationState.Opened)
    { 
       wcfC.Abort();
       wcfC = new WCFChannel();

    }    
    LastCallTime = DateTime.Now;
...