2011-12-16 2 views
5

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

«Соединение сокета было прервано. Это может быть вызвано ошибкой обработки вашего сообщения или превышением времени приема удаленным хостом или основной проблемой сетевого ресурса. 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; 
    } 
+0

Больше испытаний вышеуказанного кода доказало, что оно не работает. Оба ChannelFactory и канал открыты, но я все еще получаю эту ошибку после того, как система простаивает: Соединение сокетов было прервано. Это может быть вызвано ошибкой обработки вашего сообщения или превышением времени приема удаленным хостом или проблемой сетевого ресурса. Локальный тайм-аут гнезда был «00: 00: 59.9479970». – econner

+1

Вот ссылка от MSDN, которая показывает создание канала и канала, выполняет вызовы и закрывает канал, а затем закрывает канал. Однако, если вы используете кредитные права для аутентификации, не закрывал бы канал после каждого вызова метода и воссоздания канала до того, как каждый метод будет дорогостоящим по ресурсам и времени? http://msdn.microsoft.com/en-us/library/ms734681.aspx – econner

+0

После тестирования больше я сначала запускаю вызов службы WCF с помощью PrepareWCFConnection() ... затем вызываю мой метод обслуживания, а затем вызываю ((IClientChannel) прокси) .close(); Это закрывает соединение канала, а затем создает новый канал для каждого вызова метода. Это лучшая практика? – econner

ответ

4

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

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

+1

Хорошая точка: вы можете кэшировать фабрику каналов, но создавать каналы для каждого вызова_. – baraban

1

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

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

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

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

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

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

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

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

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

<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

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

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

    }  
    LastCallTime = DateTime.Now; 
Смежные вопросы