WCF客户端:第一次呼叫失败,第二次呼叫成功

时间:2018-05-09 09:23:16

标签: c# wcf wcf-binding

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

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

为了说明这一点,这是一张图片: SecurityNegotiationException

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>

调用外部Web服务的代码:

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测试)。
  • webservice以测试环境的管理员权限运行。
  • 测试环境中的IIS在Windows Server 2012 R2 Standard上以版本8.5.9600.16384运行

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

  • 在REST调用的同一生命周期中第二次(以及更多次,最多10次)调用SOAP Web服务(重复行 client.RequestInformation(parameters)
  • 在第一次失败的呼叫后创建一个新的MyEndpointClient,并使用新客户端执行呼叫。
  • 从证书存储中加载证书
  • 根据this blogpost (see tip 5)
  • 的建议,从文件中加载证书
  • 使用WsHttpBinding或BasicHttpBinding
  • 在安全性&gt;上使用不同的 authenticationMode customBinding中的标记。
  • 在安全性&gt;中使用 localClientSettings reconnectTransportOnFailure =“true”/&gt; 标签
  • 设置 System.Net.ServicePointManager.Expect100Continue = true;
  • 设置 System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12; (也尝试过TLS 1.0和1.1以及 Tls10 | Tls11 | Tls12 at一次)
  • 设置 System.Net.ServicePointManager.ServerCertificateValidationCallback + =(a,b,c,d)=&gt;是的; (不是一个好主意,但值得一试)
  • 设置 client.ClientCredentials.UseIdentityConfiguration = false; (也使用行为使用Web.config配置)
  • 设置 client.ClientCredentials.SupportInteractive = false; (也使用行为使用Web.config配置)

第一次调用SOAP Web服务的想法与下次调用一样稳定吗?

1 个答案:

答案 0 :(得分:0)

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

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

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

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

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