使用WCF ChannelFactory和连接超时的最佳实践

时间:2011-12-16 18:41:26

标签: wcf timeout channelfactory

我正在开发一个winform应用程序,它将访问作为Windows服务自托管的WCF服务。我使用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 个答案:

答案 0 :(得分:5)

如果你想重用一个现有的频道,你需要每隔9分钟ping一次服务来保持频道的活跃。我认为默认的接收超时是10分钟,所以如果它保持闲置超过这个频道,它将被断开。或者您可以使用可靠的会话来保持频道的活跃。

如果您不需要在同一频道上回拨,最好在完成后关闭频道并为每个服务操作重新创建一个新频道。创建频道并不昂贵。您可以缓存频道工厂,但为每个电话创建频道。

答案 1 :(得分:2)

我知道这个问题现在已经很老了,但我发现它并没有真正得到解答。有两个超时(如果你不使用可靠的消息,只有1个超时)你应该关注通道超时。在服务方面,你有&#34; ReceiveTimeout&#34;如果在超时期限内没有收到应用程序消息,则会触发该消息。此超时的默认值为10分钟。

还有&#34; InactivityTimeout&#34;仅在&#34; ReliableSession&#34;已启用。此超时是通道允许其他通信方在故障通道之前不发送任何消息的最长持续时间。

为了延长频道的使用寿命,我建议您启用&#34; ReliableSession&#34;然后设置你的&#34; ReceiveTimeout&#34; &安培; &#34; InactivityTimeout&#34;更高的价值。 ReliableSession通过发送ILM(基础设施级消息)(如保持活动状态)来确保频道保持活动状态(也发送了确认消息)。如果在&#34; InactivityTimeout&#34;之前未收到保持活动或ALM(应用程序级别消息);过期通道会出错。

此外,如果在&#34; ReceiveTimeout&#34;之前未收到ALM(应用程序级别消息);过期通道会出错。

因此,建议将两个超时增加到相同的值或设置&#34; ReceiveTimeout&#34;价值高于&#34; InactivityTimeout&#34;。

附注,设置&#34; ReceiveTimeout&#34;在客户端设置时无效,只是服务端超时。但是当在服务端使用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>

答案 2 :(得分:0)

重复使用频道的一个非常直接的解决方案,无需轮询或做任何花哨的事情,它只是处理你的频道的最后一次调用并检查wcfC.Binding.ReceiveTimeout以便在需要时重新生成它,例如:< / p>

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

    }    
    LastCallTime = DateTime.Now;