Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/wcf/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
WCF ChannelFactory和连接超时的最佳实践_Wcf_Timeout_Channelfactory - Fatal编程技术网

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

WCF ChannelFactory和连接超时的最佳实践,wcf,timeout,channelfactory,Wcf,Timeout,Channelfactory,我正在开发一个winform应用程序,该应用程序将访问作为windows服务自托管的WCF服务。我使用的是ChannelFactory而不是服务引用。我已经成功地连接和调用WCF服务。问题是,我让应用程序保持空闲20分钟,然后尝试再次调用。我收到以下错误: 套接字连接已中止。这可能是由于处理消息时出错、远程主机超过接收超时或基础网络资源问题造成的。本地套接字超时为“00:00:59.9489970” 我正在寻找管理连接的最佳实践。我目前创建了一个名为PrepareWCFConnection(见下

我正在开发一个winform应用程序,该应用程序将访问作为windows服务自托管的WCF服务。我使用的是ChannelFactory而不是服务引用。我已经成功地连接和调用WCF服务。问题是,我让应用程序保持空闲20分钟,然后尝试再次调用。我收到以下错误:

套接字连接已中止。这可能是由于处理消息时出错、远程主机超过接收超时或基础网络资源问题造成的。本地套接字超时为“00:00:59.9489970”

我正在寻找管理连接的最佳实践。我目前创建了一个名为PrepareWCFConnection(见下文)的函数,用于检查通道和通道工厂的状态。我在调用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;
    }
public bool PrepareWCFConnection()
{
如果((channelFactory==null)|
(channelFactory.State==CommunicationState.Faulted)||
(channelFactory.State!=通信状态打开))
{
channelFactory=新的channelFactory(新的NetTcpBinding(),endpointAddress);
}
if((proxy==null)||
(((IClientChannel)proxy.State==CommunicationState.Faulted)||
(((IClientChannel)proxy.State!=CommunicationState.Opened))
{
proxy=channelFactory.CreateChannel(端点地址);
((IClientChannel)代理);
}
返回true;
}

如果要重用现有频道,需要通过每9分钟ping一次服务来保持该频道的活动状态。我认为默认接收超时为10分钟,因此如果该频道保持空闲状态超过此时间,则该频道将断开连接。或者,您可以使用可靠会话来保持频道的活动状态


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

我知道这个问题现在已经很老了,但我发现它并没有得到真正的回答。有两个超时(如果您不使用可靠的消息传递,那么只有一个超时),当涉及到通道超时时,您应该关注。在服务端有“ReceiveTimeout”,如果在超时期间没有收到任何应用程序消息,则会触发该命令。此超时的默认值为10分钟

还有“InactivityTimeout”,仅在启用“ReliableSession”时使用。此超时是通道允许其他通信方在对通道进行故障处理之前不发送任何消息的最长持续时间

为了延长通道的使用寿命,我建议您启用“ReliableSession”,然后将“ReceiveTimeout”和“InactivityTimeout”设置为更高的值。ReliableSession通过发送ILM(基础架构级别的消息),如keep alive(还发送ack),使通道保持活动状态。如果在“InactivityTimeout”过期之前未收到保持活动状态或ALM(应用程序级消息),则通道将出现故障

此外,如果在“ReceiveTimeout”过期之前未收到ALM(应用程序级消息),则通道将出现故障

因此,建议将两个超时增加到相同的值,或将“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" );
服务端的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>

一个非常直截了当的解决方案,可以重用您的频道,无需轮询或做一些花哨的事情。只需处理对频道的最后一次呼叫,并检查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;

对上述代码的更多测试证明它不起作用。ChannelFactory和channel都是打开的,但是在让系统空闲后,我仍然得到这个错误:套接字连接被中止。这可能是由于处理消息时出错、远程主机超过接收超时或基础网络资源问题造成的。本地套接字超时为“00:00:59.9479970”。这里有一个来自MSDN的链接,显示如何创建channelfactory和channel,进行调用并关闭channel,然后关闭channel factory。但是,如果您使用creditials进行身份验证,那么在每次方法调用之后关闭通道,并在每次方法调用之前重新创建通道,在资源和时间上是否会很昂贵?在进行更多测试之后,我首先使用PrepareWCFConnection()启动对WCF服务的调用。。。然后调用我的服务方法,然后调用((IClientChannel)proxy.Close();这是关闭通道连接,然后为每个方法调用创建一个新通道。这是最佳做法吗?每次通话后我都会关闭频道。如果将其保持打开状态,但处于非活动状态,则10分钟后您将收到一条CommunicationFaultedException。如果你真的想保持你的频道开放,看看ReliableService。不要关闭ChannelFactory,而是重用它,因为它完成了所有的初始配置。请看一下:好的一点:您可以缓存通道工厂,但可以为每个调用创建通道。