WCF ChannelFactory 和连接超时的最佳实践
Posted
技术标签:
【中文标题】WCF ChannelFactory 和连接超时的最佳实践【英文标题】:Best Practice with WCF ChannelFactory and connection timeout 【发布时间】:2012-01-22 05:52:23 【问题描述】:我正在开发一个 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;
【问题讨论】:
对上述代码的更多测试证明它不起作用。 ChannelFactory 和通道都是打开的,但是在让系统空闲后我仍然收到此错误:套接字连接已中止。这可能是由于处理您的消息时出错或远程主机超出接收超时,或者是潜在的网络资源问题引起的。本地套接字超时为 '00:00:59.9479970'。 这是来自 MSDN 的链接,显示创建通道工厂和通道,拨打电话并关闭通道,然后关闭通道工厂。但是,如果您使用 creditials 进行身份验证,在每个方法调用之后关闭通道并在每个方法之前重新创建通道会不会耗费资源和时间? msdn.microsoft.com/en-us/library/ms734681.aspx 经过更多测试,我首先使用 PrepareWCFConnection() 开始对 WCF 服务的调用 ... 然后调用我的服务方法,然后调用 ((IClientChannel)proxy).Close();这是关闭通道连接,然后为每个方法调用创建一个新通道。这是最佳做法吗? 每次通话后我都会关闭频道。如果您保持打开但不活动,您将在 10 分钟后收到 CommunicationFaultedException。如果你真的想让你的频道保持开放,看看 ReliableService。不要关闭 ChannelFactory,而是重用它,因为它会完成所有初始配置。 看看这个:codeproject.com/Tips/507328/Creating-and-closing-of-WCF-proxies 【参考方案1】:如果您想重用现有频道,您需要通过每 9 分钟 ping 一次服务来保持频道处于活动状态。我认为默认接收超时为 10 分钟,因此如果频道保持空闲超过此时间,则会断开连接。或者,您可以使用可靠的会话来保持频道活跃。
如果您不需要在同一个频道上回调,最好在完成后关闭频道并为每个服务操作重新创建一个新频道。创建频道并不昂贵。您可以缓存频道factory ,但为每个调用创建通道。
【讨论】:
好点:您可以缓存频道工厂,但为每个调用创建频道。【参考方案2】:我知道这个问题现在已经很老了,但我发现它并没有真正得到回答。有两个超时(如果您不使用可靠消息传递,则只有 1 个)当涉及到通道超时时,您应该关注。在服务端,如果在超时期限内未收到任何应用程序消息,则会触发“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>
【讨论】:
【参考方案3】:一个非常直接的解决方案可以重用您的频道,无需轮询或做一些花哨的事情,它只需处理对您的频道的最后一次调用并检查 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;
【讨论】:
以上是关于WCF ChannelFactory 和连接超时的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章
WCF ChannelFactory 和通道 - 缓存、重用、关闭和恢复
WCF,ChannelFactory,“找不到端点元素...”
ChannelFactory:Channel Close() 未关闭连接(netstat 显示 ESTABLISHED)
ASP.NET 客户端应用程序中的 WCF ChannelFactory 和 Channel 缓存
WCF ChannelFactory 转换接口到 IClientChannel 可疑转换
带有 ChannelFactory 的 WCF 客户端,方法返回 ProtocolException / 405 Method not Allowed