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);

更多信息:

我尝试过但没有解决问题的方法:

有什么想法可以使对 SOAP 网络服务的第一次调用与下一次调用一样稳定吗?

出于某种原因,这只发生在一台测试服务器上,而不是其他服务器上。 调用外部 SOAP 网络服务的跟踪日志显示内部函数 AcquireCredentialsHandle 失败,错误代码为 0X8009030D.

经过更多调查后,我发现有几个证书(来自外部 SOAP 网络服务)安装在有问题的服务器上。它们似乎与对外部 SOAP 网络服务的调用冲突。删除这些证书后,现在第一次调用成功了!

更新: 我又遇到了同样的问题,不过现在是在我的开发机器上。清理证书没有帮助,所有 请求都因相同的 SecurityNegotiationException 而失败。为了解决这个问题,我添加了 HTTP 100 状态代码的传递,并强制连接到 TLS 1.2:

ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

请注意,我在初始化 WCF 客户端(问题 post 中的 MyEndpointClient)之前 添加了这段代码,以便确保 WCF 客户端使用这些设置。