WCF Silverlight客户端获取404时未找到轮询消息的响应



最终,WCF双工Silverlight 4客户端在从WCF服务向Silverlight客户端发送轮询后立即开始收到轮询消息的404 Not Found错误,有时第二次轮询会发生这种情况,有时连接工作数小时甚至数天,但大多在第一分钟失败。

有趣的是,当使用MaxMessagesPerPoll双工模式时,这个问题就像已知的Silverlight 4错误一样,这里和这里都描述了解决方案,但我使用的是SingleMessagePerPoll模式。我试着按照建议使用ClientStack,但没有任何改变。

一般流程:

  1. SL客户端执行WCF服务方法,收到响应
  2. 然后立即SL客户端开始向服务发送轮询消息,然后获得第二个或N-s轮询消息的异常

    System.Net.WebException:远程服务器返回错误:NotFound

  3. Fiddler仅显示轮询消息的空404响应
  4. 然后引发客户端通道故障事件

在发生这样的故障后,我正在尝试重新连接SL客户端,单次重新连接重试流:

  1. 处理Faulted事件
  2. 取消订阅所有频道事件,如Closed/Closing/Opened/Opening
  3. 使用try { close } catch { abort }正确关闭通道
  4. 以下都在一个新的线程轮询线程中:(我发现这工作稍微稳定一点——请参阅本文)
  5. 等待45-70秒
  6. 使用相同的DuplexChannelFactory<T>实例创建一个新通道,订阅所有通道事件,仅用于日志记录
  7. 执行WCF服务方法

重试1-10次(约1-10分钟)后,客户端最终连接到服务器并继续正常轮询。

在WCF服务日志中,我看到它得到了所有cleint请求,处理得没有任何异常,所以Silverlight客户端似乎发生了一些事情。

一般信息:

  • .NET Framework 4.0
  • 轮询双工
  • 异步WCF方法
  • IIS 6.0承载的WCF服务
  • Silverligth 4客户端
  • 客户端操作系统:Windows XP SP2
  • 服务器操作系统:Windows 2003 R2 SP2
  • NTLM身份验证
  • 双工模式:单消息轮询
  • 还有一个WCF服务在我的服务开始工作之前进行请求/回复,它不使用双工连接
  • 在SL客户端服务上,我将所有内容都记录到UI中,以便查看所有事件流,并为每个特定事件留出时间
  • IIS日志、服务器事件日志中没有错误

客户端:

var binaryBinding = new BinaryMessageEncodingBindingElement();
binaryBinding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
var httpbindingElement = new HttpTransportBindingElement
{
MaxReceivedMessageSize = 131072
};
var pollingDuplexBindingElement = new PollingDuplexBindingElement
{
ClientPollTimeout = new TimeSpan(0, 0, 1, 30),
InactivityTimeout = new TimeSpan(0, 8, 0, 0),
};

_binding = new CustomBinding(
pollingDuplexBindingElement,
binaryBinding,
httpbindingElement)
{
SendTimeout = new TimeSpan(0, 0, 0, 45),
CloseTimeout = new TimeSpan(0, 0, 0, 25),
ReceiveTimeout = new TimeSpan(0, 8, 0, 0),
OpenTimeout = new TimeSpan(0, 0, 0, 45)
};

httpbindingElement.AuthenticationScheme = AuthenticationSchemes.Negotiate;
var endpoint = new EndpointAddress(_endpointAddress);
_channelFactory = new DuplexChannelFactory<TWebService>(
new InstanceContext(instanceOfClientServiceClass), 
_binding, 
endpoint);

// then this factory used to create a new channels
// Also for a new channel I'm setting OpTimeout
var contextChannel = newChannel as IContextChannel;
if (contextChannel != null)
{
contextChannel.OperationTimeout = TimeSpan.FromSeconds(45);
}

服务器:

  • WCF,PerSession,多线程
  • 一切都是线程安全的
  • 执行时没有服务器服务异常
  • 大量的日志记录,这样我就可以看到服务上发生了什么
  • 所有WCF跟踪都使用switchValueAll启用,没有任何可疑之处
<binding name="customName"
sendTimeout="00:01:00"
receiveTimeout="08:00:00"
openTimeout="00:01:00"
closeTimeout="00:00:35">
<pollingDuplex
inactivityTimeout="08:00:00"
serverPollTimeout="00:01:00" />
<binaryMessageEncoding />
<httpTransport authenticationScheme="Ntlm"
maxReceivedMessageSize="131072">              
</httpTransport>
</binding>
<behavior name="customBehavior">
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceThrottling
maxConcurrentCalls = "500"
maxConcurrentSessions = "500"
maxConcurrentInstances = "500" />
</behavior>

如果一切正常,那么这可能是网络基础设施/配置问题(例如dns配置)。当在本地运行或使用ip地址而不是主机名时,你会遇到同样的问题吗?

如果您在IIS中的站点上配置了多个绑定,也可能会出现类似的问题(有关详细信息,请参阅此处:http://blogs.msdn.com/b/rampo/archive/2008/02/11/how-can-wcf-support-multiple-iis-binding-specified-per-site.aspx)

另一件事是如何从服务器到客户端进行通信。如果您在循环中迭代客户端并逐个调用回调方法,那么您可能会得到超时,显示为404。回调通常应该在后台线程上调用(每个客户端一个)。

根据您的通信方式,这也可能是由死锁引起的(当UI线程参与向服务发送/接收消息/回调以及从服务接收消息/回叫时)。

在调查为PerSession WCF服务调用两次的StackOverflow后静态构造函数中描述的问题时,我发现当我将底层AppPoolIIS配置切换为使用单个工作进程而不是之前指定的2时,Polling Duplex开始稳定工作。我不知道为什么之前设置了2,因为我没有这个服务器,但无论如何,这就是我现在所拥有的-在同一台机器上启动的多个Silverlight客户端工作稳定,轮询轮询,没有404错误,所有客户端在IIS重新启动并回收后,都会在1尝试重新连接。。。

有关更多详细信息,请参阅性能应用程序池设置

TL;DR:当IIS托管的WCF驻留在具有多个工作进程的AppPool中时,轮询双工会变得不稳定。因此,在高负载的情况下,IIS启动了第二个进程,并开始在第二个过程中创建WCF服务实例,所以当客户端会话在一个进程中创建时,我遇到了这样的情况,但似乎轮询有时会到达另一个进程,而该进程不知道当前的连接/会话,所以开始拒绝此类消息和整个连接故障。

因此,Polling Duplex在设计上无法在单个IIS服务器和AppPool范围内的多个进程之间扩展,换句话说,如果您有一个以上的工作进程-这是WebGarden环境,双工无法在web农场和花园之间扩展

相关内容

  • 没有找到相关文章

最新更新