WCF 客户端:第一次调用失败,第二次调用成功
WCF Client: First call fails, second call succeeds
我有一个 REST 网络服务,它使用 WCF 客户端调用外部 SOAP 网络服务。此 REST 网络服务托管在我们测试环境的 IIS 中。
当调用 REST 网络服务,然后调用外部网络服务(使用 WCF 客户端)时,在 IIS 中重新启动 REST 网络服务后,WCF 客户端的第一次调用抛出 SecurityNegotiationException。对 REST web 服务的第二次调用,并间接和所有后续调用成功。
为了说明这一点,这里有一张图片:
这个SecurityNegotiationException如下:
System.ServiceModel.Security.SecurityNegotiationException: Could not establish secure channel for SSL/TLS with authority 'X'.
---> System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
端点和绑定如下(通过添加服务引用生成,稍微修改了customBinding):
<endpoint address="https://..." binding="customBinding" bindingConfiguration="MyBinding" contract="WS_..." name="MyEndpoint" />
...
<customBinding>
<binding name="MyBinding">
<textMessageEncoding messageVersion="Soap11" />
<security authenticationMode="UserNameOverTransport" />
<httpsTransport requireClientCertificate="true" />
</binding>
</customBinding>
调用外部webservice的代码:
MyEndpointClient client = new MyEndpointClient("MyEndpoint");
client.ClientCredentials.UserName.UserName = authInfo.Username;
client.ClientCredentials.UserName.Password = authInfo.Password;
client.ClientCredentials.ClientCertificate.Certificate = authInfo.Certificate;
var result = client.requestInformation(parameters); // This fails the first time after IIS restart.
authInfo.Certificate 正在加载如下:
authInfo.Certificate = new X509Certificate2(certificateBytes, certificatePassword);
更多信息:
- 当我 运行 本地 REST web 服务时,第一次使用 WCF 客户端调用外部服务工作正常(以及所有后续调用)。
- 我已通过添加服务引用将 SOAP 网络服务 WSDL 添加到项目中。
- 此网络服务需要用户名和密码以及证书。必须使用WSE3.0 (Windows Security Extensions),我不能使用WSE2.0.
- 证书在每种情况下都正确加载,我使用 try-catch 创建 X509Certificate2,它捕获 CryptographicException 并取消 REST-web 服务中的进一步处理(对 SOAP web 服务的调用不会被执行)。我已验证我正在测试的证书是有效的。
- 添加外部 SOAP 网络服务 WSDL 时,它会生成自定义绑定(因此不是我手动尝试过的 basicHttpBinding 或 WsHttpBinding)。
- 外部 SOAP 网络服务支持 TLS 1.0、1.1 和 1.2(使用 SSLLabs 测试)。
- Web 服务 运行 在测试环境中具有管理员权限。
- IIS 测试环境 运行s 版本 8.5.9600.16384 Windows Server 2012 R2 Standard
我尝试过但没有解决问题的方法:
- 在 REST 调用的同一生命周期中,在第一次调用 SOAP web 服务后第二次(以及更多次,最多 10 次)(重复行 client.RequestInformation(参数))
- 在第一次调用失败后创建一个新的 MyEndpointClient,并使用新客户端执行调用。
- 正在从证书存储区加载证书
- 根据 this blogpost (see tip 5)
的建议从文件加载证书
- 使用 WsHttpBinding 或 BasicHttpBinding
- 在 customBinding 的 security> 标签上使用不同的 authenticationMode。
- 在安全>标签
中使用localClientSettings reconnectTransportOnFailure="true" />
- 设置System.Net.ServicePointManager.Expect100Continue = true;
- 设置 System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;(还尝试了 TLS 1.0 和 1.1 以及 Tls10 | Tls11 | Tls12一次)
- 设置 System.Net.ServicePointManager.ServerCertificateValidationCallback += (a,b,c,d) => true;(不是个好主意,但值得一试)
- 设置 client.ClientCredentials.UseIdentityConfiguration = false;(也使用 Web.config 配置使用行为)
- 设置 client.ClientCredentials.SupportInteractive = false;(也使用 Web.config 配置使用行为)
有什么想法可以使对 SOAP 网络服务的第一次调用与下一次调用一样稳定吗?
出于某种原因,这只发生在一台测试服务器上,而不是其他服务器上。
调用外部 SOAP 网络服务的跟踪日志显示内部函数 AcquireCredentialsHandle
失败,错误代码为 0X8009030D
.
经过更多调查后,我发现有几个证书(来自外部 SOAP 网络服务)安装在有问题的服务器上。它们似乎与对外部 SOAP 网络服务的调用冲突。删除这些证书后,现在第一次调用成功了!
更新: 我又遇到了同样的问题,不过现在是在我的开发机器上。清理证书没有帮助,所有 请求都因相同的 SecurityNegotiationException 而失败。为了解决这个问题,我添加了 HTTP 100 状态代码的传递,并强制连接到 TLS 1.2:
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
请注意,我在初始化 WCF 客户端(问题 post 中的 MyEndpointClient)之前 添加了这段代码,以便确保 WCF 客户端使用这些设置。
我有一个 REST 网络服务,它使用 WCF 客户端调用外部 SOAP 网络服务。此 REST 网络服务托管在我们测试环境的 IIS 中。
当调用 REST 网络服务,然后调用外部网络服务(使用 WCF 客户端)时,在 IIS 中重新启动 REST 网络服务后,WCF 客户端的第一次调用抛出 SecurityNegotiationException。对 REST web 服务的第二次调用,并间接和所有后续调用成功。
为了说明这一点,这里有一张图片:
这个SecurityNegotiationException如下:
System.ServiceModel.Security.SecurityNegotiationException: Could not establish secure channel for SSL/TLS with authority 'X'. ---> System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
端点和绑定如下(通过添加服务引用生成,稍微修改了customBinding):
<endpoint address="https://..." binding="customBinding" bindingConfiguration="MyBinding" contract="WS_..." name="MyEndpoint" />
...
<customBinding>
<binding name="MyBinding">
<textMessageEncoding messageVersion="Soap11" />
<security authenticationMode="UserNameOverTransport" />
<httpsTransport requireClientCertificate="true" />
</binding>
</customBinding>
调用外部webservice的代码:
MyEndpointClient client = new MyEndpointClient("MyEndpoint");
client.ClientCredentials.UserName.UserName = authInfo.Username;
client.ClientCredentials.UserName.Password = authInfo.Password;
client.ClientCredentials.ClientCertificate.Certificate = authInfo.Certificate;
var result = client.requestInformation(parameters); // This fails the first time after IIS restart.
authInfo.Certificate 正在加载如下:
authInfo.Certificate = new X509Certificate2(certificateBytes, certificatePassword);
更多信息:
- 当我 运行 本地 REST web 服务时,第一次使用 WCF 客户端调用外部服务工作正常(以及所有后续调用)。
- 我已通过添加服务引用将 SOAP 网络服务 WSDL 添加到项目中。
- 此网络服务需要用户名和密码以及证书。必须使用WSE3.0 (Windows Security Extensions),我不能使用WSE2.0.
- 证书在每种情况下都正确加载,我使用 try-catch 创建 X509Certificate2,它捕获 CryptographicException 并取消 REST-web 服务中的进一步处理(对 SOAP web 服务的调用不会被执行)。我已验证我正在测试的证书是有效的。
- 添加外部 SOAP 网络服务 WSDL 时,它会生成自定义绑定(因此不是我手动尝试过的 basicHttpBinding 或 WsHttpBinding)。
- 外部 SOAP 网络服务支持 TLS 1.0、1.1 和 1.2(使用 SSLLabs 测试)。
- Web 服务 运行 在测试环境中具有管理员权限。
- IIS 测试环境 运行s 版本 8.5.9600.16384 Windows Server 2012 R2 Standard
我尝试过但没有解决问题的方法:
- 在 REST 调用的同一生命周期中,在第一次调用 SOAP web 服务后第二次(以及更多次,最多 10 次)(重复行 client.RequestInformation(参数))
- 在第一次调用失败后创建一个新的 MyEndpointClient,并使用新客户端执行调用。
- 正在从证书存储区加载证书
- 根据 this blogpost (see tip 5) 的建议从文件加载证书
- 使用 WsHttpBinding 或 BasicHttpBinding
- 在 customBinding 的 security> 标签上使用不同的 authenticationMode。
- 在安全>标签 中使用localClientSettings reconnectTransportOnFailure="true" />
- 设置System.Net.ServicePointManager.Expect100Continue = true;
- 设置 System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;(还尝试了 TLS 1.0 和 1.1 以及 Tls10 | Tls11 | Tls12一次)
- 设置 System.Net.ServicePointManager.ServerCertificateValidationCallback += (a,b,c,d) => true;(不是个好主意,但值得一试)
- 设置 client.ClientCredentials.UseIdentityConfiguration = false;(也使用 Web.config 配置使用行为)
- 设置 client.ClientCredentials.SupportInteractive = false;(也使用 Web.config 配置使用行为)
有什么想法可以使对 SOAP 网络服务的第一次调用与下一次调用一样稳定吗?
出于某种原因,这只发生在一台测试服务器上,而不是其他服务器上。
调用外部 SOAP 网络服务的跟踪日志显示内部函数 AcquireCredentialsHandle
失败,错误代码为 0X8009030D
.
经过更多调查后,我发现有几个证书(来自外部 SOAP 网络服务)安装在有问题的服务器上。它们似乎与对外部 SOAP 网络服务的调用冲突。删除这些证书后,现在第一次调用成功了!
更新: 我又遇到了同样的问题,不过现在是在我的开发机器上。清理证书没有帮助,所有 请求都因相同的 SecurityNegotiationException 而失败。为了解决这个问题,我添加了 HTTP 100 状态代码的传递,并强制连接到 TLS 1.2:
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
请注意,我在初始化 WCF 客户端(问题 post 中的 MyEndpointClient)之前 添加了这段代码,以便确保 WCF 客户端使用这些设置。