底层连接已关闭:服务器已关闭预期保持活动状态的连接。
使用.Net 4.0 Web服务客户端与ONVIF网络设备进行通信时,我们经常会遇到此异常。
查看packet captures,这似乎是一个不符合HTTP规范并在发送响应后关闭连接的设备,而HTTP/1.1
默认保持活动状态。
这导致客户端(WCF)在服务器刚刚关闭它时尝试重用连接,
在制造商解决这个问题之前,有什么办法可以告诉Web服务/ SOAP客户端不要使用持久连接吗?
请注意,修改标头以使用Connection: Close
不会有帮助,除非它正在关闭,但SOAP客户端希望它保持打开状态。
答案 0 :(得分:2)
但有什么办法可以告诉Web服务/ SOAP客户端不要使用持久连接吗?
是,您可以将InstanceContextMode
设置为PerCall
,它会创建新的InstanceContext
对象,然后在每次调用之后创建并回收。
换句话说,当我们按照调用配置WCF服务时,会为通过WCF代理客户端进行的每个方法调用创建新的服务实例。
您可以像以下一样使用它:
在ServiceBehavior
上设置合同接口实施,如:
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
public class CalculatorService : ICalculator
{
...
}
更新 -
根据您的评论,似乎解决方案是明确将KeepAlive
属性设置为FALSE
。
可以通过多种方式完成:
<强>代码强>
我实际上不知道你对代码有多少控制权。但是在你正在消费服务的客户端,我们可以改变这种行为,如:
protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)base.GetWebRequest(uri);
webRequest.KeepAlive = false;
return webRequest;
}
或
namespace YourNamespace
{
using System.Diagnostics;
using System.Web.Services;
using System.ComponentModel;
using System.Web.Services.Protocols;
using System;
using System.Xml.Serialization;
/// <summary>
/// This partial class makes it so all requests specify
/// "Connection: Close" instead of "Connection: KeepAlive" in the HTTP headers.
/// </summary>
public partial class YourServiceNameWse : Microsoft.Web.Services3.WebServicesClientProtocol
{
protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)base.GetWebRequest(uri);
webRequest.KeepAlive = false;
return webRequest;
}
}
}
IIS设置
此外,您可以使用 CommandLine 设置IIS上的特定网站,如:
appcmd.exe set config "<Your Web Site Here>" -section:system.webServer/httpProtocol /allowKeepAlive:"False"
<强>的Web.Config 强>
<configuration>
<system.webServer>
<httpProtocol allowKeepAlive="false" />
</system.webServer>
</configuration>
我希望它能以某种方式帮助你。
答案 1 :(得分:1)
底层HttpWebRequest
是在生成的客户端类使用的HttpChannelFactory
中创建的。
这是从公开HttpTransportBindingElement
属性的KeepAliveEnabled
创建的。
绑定元素是在WSHttpBinding
类内部创建的,可以通过覆盖GetTransport()
来更改。
private class WSHttpBindingNoKeepAlive : WSHttpBinding {
public WSHttpBindingNoKeepAlive(SecurityMode securityMode)
: base(securityMode) {
}
protected override TransportBindingElement GetTransport() {
TransportBindingElement transport = base.GetTransport();
if (transport is HttpTransportBindingElement) {
((HttpTransportBindingElement)transport).KeepAliveEnabled = false;
}
return transport;
}
}
然后可以使用此覆盖...Binding
类,如:
WSHttpBindingNoKeepAlive clientBinding = new WSHttpBindingNoKeepAlive(SecurityMode.None);
EndpointAddress address = new EndpointAddress(this.deviceUrl);
WSNameSpace.WSClient client = new WSNameSpace.WSClient(clientBinding, address);