【问题标题】:WCF Client: First call fails, second call succeedsWCF 客户端:第一次调用失败,第二次调用成功
【发布时间】:2018-10-19 08:42:00
【问题描述】:

我有一个 REST 网络服务,它使用 WCF 客户端调用外部 SOAP 网络服务。此 REST Web 服务托管在我们测试环境的 IIS 中。

当调用 REST Web 服务,然后调用外部 Web 服务(使用 WCF 客户端)时,在 IIS 中重新启动 REST Web 服务后,WCF 客户端的第一次调用会引发 SecurityNegotiationException。对 REST Web 服务的第二次调用,以及间接和所有后续调用均成功。

为了说明这一点,这里有一张图片:

这个SecurityNegotiationException如下:

System.ServiceModel.Security.SecurityNegotiationException:无法为具有权限“X”的 SSL/TLS 建立安全通道。 ---> System.Net.WebException:请求被中止:无法创建 SSL/TLS 安全通道。

端点和绑定如下(通过添加服务引用生成,稍微修改了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 Web 服务 WSDL 添加到项目中。
  • 此 Web 服务需要用户名和密码以及证书。必须使用 WSE3.0(Windows 安全扩展),我不能使用 WSE2.0。
  • 证书在每种情况下都能正确加载,我已经使用 try-catch 创建 X509Certificate2,它捕获 CryptographicException 并取消 REST-webservice 中的进一步处理(对 SOAP webservice 的调用不会被执行)。我已验证我正在测试的证书是有效的。
  • 添加外部 SOAP Web 服务 WSDL 时,它会生成自定义绑定(因此不是我手动尝试过的 basicHttpBinding 或 WsHttpBinding)。
  • 外部 SOAP Web 服务支持 TLS 1.0、1.1 和 1.2(使用 SSLLabs 测试)。
  • Web 服务在测试环境中以管理员权限运行。
  • 测试环境中的 IIS 在 Windows Server 2012 R2 Standard 上的版本 8.5.9600.16384 上运行

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

  • 在第一次之后,在 REST 调用的同一生命周期内再次调用 SOAP Web 服务(更多次,最多 10 次)(重复行 client.RequestInformation(parameters) )
  • 在第一次调用失败后创建新的 MyEndpointClient,并使用新客户端执行调用。
  • 从证书存储加载证书
  • 根据this blogpost (see tip 5) 的建议从文件加载证书
  • 使用 WsHttpBinding 或 BasicHttpBinding
  • 在 customBinding 中的 security> 标记上使用不同的 authenticationMode
  • 在 security> 标签中使用 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 网络服务的第一次调用与下一次调用一样稳定吗?

【问题讨论】:

  • tl;博士。我认为部分症状来自 WCF Channel 属性:在发生故障后,它仍然是故障。确保备份并创建一个新通道(客户端对象)。

标签: c# wcf wcf-binding


【解决方案1】:

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 2019-10-20
    • 2012-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多