我的计算机(Windows 8)中的Windows窗体应用程序(C#/ .NET 4)中运行了两个WCF服务:
第二项服务:https://local_192-168-1-104.desktop.Company.com:9003
第一个服务在本地访问,第二个服务由本地网络中的其他计算机访问。主机:local_192-168-1-104.desktop.Company.com由DNS解析为ip:192.168.1.104,这是我的本地网络IP地址。
两种服务都使用https,第一种使用自签名证书,第二种使用证书:desktop.Company.com
问题:经过一段时间不活动后,第二个服务停止工作。
不记录任何异常,并且不执行WebServiceHost的事件Faulted(),UnknownMessageReceived(),Closing()或Closed()。
如果我关闭应用程序并再次启动,则问题仍然存在。在此错误情况下,WebServiceHost的State属性为" Opened",但服务不响应。
如果我停止服务,请重新配置服务(主题:配置证书服务2),然后再次启动,问题会停止一段时间。
我使用以下方法测试wcf服务:
using (WebClient webClient = new WebClient())
{
webClient.DownloadDataCompleted += webClient_DownloadDataCompleted;
webClient.DownloadDataAsync(new Uri("https://local_192-168-1-104.desktop.Company.com:9003/Message/Test"));
}
我收到了这个例外:
基础连接已关闭:发送时发生意外错误。
>> INNER EXCEPTION:
Message: An existing connection was forcibly closed by the remote host
Type: System.Net.Sockets.SocketException (System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
Source: System
TargetSite: Int32 EndReceive(System.IAsyncResult)
ErrorCode: 10054
StackTrace:
---------------------------
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
---------------------------
Windows错误代码 10054 是:
由同行重置连接。
远程主机强行关闭现有连接。这个 通常在远程主机上的对等应用程序结果时生成 突然停止,主机重启,主机或远程网络 接口被禁用,或远程主机使用硬关闭(请参阅 setsockopt有关远程SO_LINGER选项的更多信息 插座)。如果由于连接断开,也可能导致此错误 保持活动活动在一个或多个操作时检测到故障 正在进行中。正在进行的操作失败了 WSAENETRESET。后续操作因WSAECONNRESET而失败。
我尝试禁用Keep Alive,但问题仍然存在。
以下详细信息:
配置证书服务1
netsh http delete urlacl url=https://+:9002/
netsh http delete sslcert ipport=0.0.0.0:9002
netsh http add urlacl url=https://+:9002/ user=Everyone
makecert -sk RootCA -sky signature -pe -n CN=localhost -r -sr LocalMachine -ss Root certificate\CustomCertificate_MyCA.cer
makecert -sk server -sky exchange -pe -n CN=localhost -ir LocalMachine -is Root -ic certificate\CustomCertificate_MyCA.cer -sr LocalMachine -ss My certificate\CustomCertificate.cer
(install certificate in CertificateStore)
netsh http add sslcert ipport=0.0.0.0:9002 certhash=F3F40BF81AF0.... appid={00a1d32c-68bd-4693-a872-...}
启动服务1
var mainServiceHost = new Company.Library.WCF.JSONServiceHost("localhost", 9002, true);
mainServiceHost.Start(typeof(Service.Message), typeof(Service.IMessage), false);
配置证书服务2
netsh http delete urlacl url=https://+:9002/
netsh http delete sslcert ipport=192.168.1.146:9003
netsh http add urlacl url=https://+:9003/ user=Everyone
(install certificate in CertificateStore)
netsh http add sslcert ipport=192.168.1.146:9003 certhash=1C36C9C... appid={00a1d32c-68bd-4693-a872-1473...}
启动服务2
var localServerServiceHost = new Company.Library.WCF.JSONServiceHost("local_192-168-1-104.desktop.Company.com", 9003, true);
localServerServiceHost.Start(typeof(Service.Message), typeof(Service.IMessage), false);
JSONServiceHost类
public void Start(Type serviceType, Type implementedContract, bool keepAliveEnabled)
{
EndpointAddress endpoint = new EndpointAddress(Url);
CustomServiceBehavior serviceBehavior = new CustomServiceBehavior();
svcWebHost.Description.Behaviors.Add(serviceBehavior);
BindingElementCollection bindingElements;
WebHttpBinding binding = new WebHttpBinding(WebHttpSecurityMode.Transport);
bindingElements = binding.CreateBindingElements();
if (bindingElements != null)
{
var transport = bindingElements.Find<HttpsTransportBindingElement>();
if (transport != null)
transport.KeepAliveEnabled = keepAliveEnabled;
}
binding.ReaderQuotas.MaxArrayLength = int.MaxValue;
binding.ReaderQuotas.MaxBytesPerRead = int.MaxValue;
binding.ReaderQuotas.MaxDepth = int.MaxValue;
binding.ReaderQuotas.MaxNameTableCharCount = int.MaxValue;
binding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
binding.MaxBufferSize = int.MaxValue;
binding.MaxBufferPoolSize = int.MaxValue;
binding.MaxReceivedMessageSize = int.MaxValue;
binding.SendTimeout = TimeSpan.FromMinutes(5);
binding.ReceiveTimeout = TimeSpan.FromMinutes(5);
binding.OpenTimeout = TimeSpan.FromMinutes(5);
binding.CloseTimeout = TimeSpan.FromMinutes(5);
ServiceEndpoint serviceEndpoint = svcWebHost.AddServiceEndpoint(implementedContract, binding, endpoint.Uri);
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
svcWebHost.Description.Behaviors.Add(smb);
ServiceDebugBehavior sdb = svcWebHost.Description.Behaviors.Find<ServiceDebugBehavior>();
if (sdb != null)
sdb.IncludeExceptionDetailInFaults = true;
foreach (var operation in serviceEndpoint.Contract.Operations)
operation.Behaviors.Add(new CustomOperationBehavior());
svcWebHost.Open();
}
应用程序启动时执行的条件配置
private static void ConfigureGlobalServiceParameters()
{
System.Net.ServicePointManager.CheckCertificateRevocationList = false;
System.Net.ServicePointManager.DefaultConnectionLimit = int.MaxValue;
System.Net.ServicePointManager.DnsRefreshTimeout = -1;
System.Net.ServicePointManager.Expect100Continue = false;
System.Net.ServicePointManager.MaxServicePointIdleTime = 20 * 1000;
System.Net.ServicePointManager.MaxServicePoints = 10;
System.Net.ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(delegate { return true; });
System.Net.ServicePointManager.UseNagleAlgorithm = false;
System.Net.ServicePointManager.SetTcpKeepAlive(false, 0, 0);
}
CustomEndpointBehavior
public class CustomEndpointBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
var customInspector = new CustomDispatchMessageInspector();
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(customInspector);
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
CustomOperationBehavior
public class CustomOperationBehavior : IOperationBehavior
{
public void AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.ClientOperation clientOperation)
{
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)
{
}
public void Validate(OperationDescription operationDescription)
{
}
}
CustomServiceBehavior
public class CustomServiceBehavior : IServiceBehavior
{
public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
CustomEndpointBehavior endpointBehavior = new CustomEndpointBehavior();
foreach (var endpoint in serviceDescription.Endpoints)
endpoint.Behaviors.Add(endpointBehavior);
}
public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
}
}
谢谢!
答案 0 :(得分:1)
我回到这个问题,最后找到了解决方案。
这不是WCF的问题,WCF停止工作,因为证书与Windows端口的关联不起作用。
问题:
<强>后果:强>
在Windows重新启动后,服务停止在此端口中工作,并且会出现以下描述的行为:
如果您尝试对url执行Http请求,则会收到以下错误: 基础连接已关闭:发送时发生意外错误。
如果您尝试再次将证书关联到端口,请使用以下命令:
命令:netsh http add sslcert ipport=192.168.1.146:9003 certhash=1C36.. appid={00a1..}
您收到此错误:
SSL证书添加失败,错误:1312 指定的登录会话不存在。它可能已经被终止。
命令:certutil -exportPFX -p "[password]" My [cert_SerialNumber] "c:\temp\desktop.pfx" NoChain
您收到此错误:
私钥不可导出 加密测试通过 CertUtil:-exportPFX命令FAILED:0x8009000b(-2146893813 NTE_BAD_KEY_STATE) CertUtil:密钥无法在指定状态下使用。
如何重现所有配置过程:
代码:X509Certificate2 certificate = new X509Certificate2(certPath, password);
将证书证书添加到CertificateStore(StoreName:“MY”,StoreLocation:LocalMachine):
X509Store store = new X509Store(storeName.My,StoreLocation.LocalMachine); store.Open(OpenFlags.ReadWrite); store.Add(证书); store.Close();
将证书附加到端口:
命令:netsh http add sslcert ipport=192.168.1.146:9003 certhash=1C36C... appid={00a..} clientcertnegotiation=enable
(我这样做,因为我正在从本地网络中的另一台计算机访问WCF)
如何手动解决问题:
在本文中: http://www.hanselman.com/blog/WorkingWithSSLAtDevelopmentTimeIsEasierWithIISExpress.aspx
有这个解决方案:
我认为将自签名证书从“个人”转移到“受信任的根” CA目录导致SSL在开发人员之后停止工作的问题 重启他们的机器。 (不知道它是如何发生的,但它确实发生了 始终如一。)我终于通过导出和重新导入解决了这个问题 将自签名证书放入受信任的根目录(而不是 只需拖动它)。现在我的自签名证书被认为是我 每次重新启动时都不需要重新安装/修复IIS Express 机。
奇迹般地,您无需从个人证书存储区导出证书,并以Root身份导入证书。您只需要在Windows重新启动之前手动导出证书,并且在Windows重新启动后不会发生此问题。
如何使用命令行解决问题:
在配置过程之后,在第一次Windows重启之前,执行以下命令:
命令:certutil -f -p "[password]" -importpfx My "c:\temp\cert.pfx"
命令:certutil -exportPFX -p "[password]" My [certificate_Serial_Number] "c:\temp\cert2.pfx" NoChain
有价值的信息:
列出Windows Local Machine Certification Store中安装的证书:
使用命令“netsh http add sslcert”列出与端口关联的证书
命令:certutil -store "My"
命令:netsh http delete sslcert ipport=192.168.1.104:9003