背景
最近需要将一些外部的 web Service 及其他 SOAP 接口的调用移到一个独立的 WebAPI 项目中, 然后供其他. Net Core 项目调用. 之前的几个 Web Service 已经成功迁移, 但是在迁移一个需要用户名密码认证的 SOAP 接口的时候却始终调用不成功. 下面直接上代码.
示例代码
在. net framework 中通过添加服务引用会自动在 Web.config(或者 App.config)中生成类似以下绑定配置:
- <system.serviceModel>
- <bindings>
- <customBinding>
- <binding name="binding">
- <mtomMessageEncoding ="Soap11WSAddressing10" />
- <httpTransport authenticationScheme="Basic"/>
- </binding>
- </customBinding>
- </bindings>
- <client>
- <endpoint address="http://sampl.url" binding="customBinding" bindingConfiguration="binding" contract="TestClient" name="binding" />
- </client>
- </system.serviceModel>
可以直接调用 client 的无参构造函数 (会从配置中读取相应的配置) 来获取客户端实例, 但是由于. net core 中已经不支持 Web.config(或者 App.config), 因此需要自己通过代码来创建 binding 和 EndpointAddress 来获取客户端实例
- var binding = new CustomBinding(new HttpTransportBindingElement
- {
- AuthenticationScheme = AuthenticationSchemes.Basic
- });
- var client = new TestClient(binding, new EndpointAddress(new Uri("http://sample.url")));
- client.ClientCredentials.UserName.UserName = "admin";
- client.ClientCredentials.UserName.Password = "123456";
- var response = client.Add(new Request()).Result
发现问题
在测试过程中始终抛异常 The server returned an invalid or unrecognized response.. 使用上面相同的代码在. net framework 里测试却能正常获取响应, 初步判断应该是. net core 中的问题. 通过 wireshark 工具抓包比对, 我发现了差别.
请求正常的抓包截图
请求失败的抓包截图
通过两个请求的比对发现, 失败的请求头部信息中没有 Authorization 信息. 接着我使用 HttpClient 发送 post 请求来模拟对 SOAP 接口的调用.
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", "YWRtaW46MTIzNDU2==");
在设置和不设置 Authorization 的分别测试中发现设置了 Authorization 能够成功请求并获得响应, 不设置 Authorization 的请求获得了一段 html 格式的文本响应, 其中有一段很说明问题 HTTP 401 - Unauthorized. 在这两个不同的请求抓包中也发现成功的请求头部中是包含 Authorization 信息的, 另一个则没有. 因此基本断定问题就出现在这里.
如何解决
问题找到了, 是因为请求头部中缺少 Authorization 信息, 但是如何解决我却始终没有找到好的办法, SOAP 接口的调用不像使用 HttpClient 发送 post 请求可以对 header 进行修改. 直接使用 HttpClient 发送 post 请求来调用 SOAP 接口对 xml 的序列化和反序列化又很是麻烦, 也不想使用这种过于牵强的做法. 翻遍了博客园和 stackoverfolw 也始终没有找到解决办法.
终于, 在我不懈的努力中看到了曙光, 在 GitHub 上翻 dotnet/wcf 的 Issues 的时候找到一些相关东西, 特别是这一条 https://github.com/dotnet/wcf/issues/3008 . 其中提到 System.Private.ServiceModel 版本高于或等于 4.5.0 的时候会抛异常 The server returned an invalid or unrecognized response., 虽然他的使用跟我的不太一样, 但是异常信息却相同. 我当即将版本降到 4.4.4 再次测试, 结果令人惊喜, 请求成功了, 通过抓包分析 Authorization 信息在请求头部中. 这证实我之前的判断, 就是因为没有 Authorization 信息导致请求失败.
结语
问题解决了, System.Private.ServiceModel4.5.0 及以上版本会存在此问题, 降级到 4.4.4 方可解决, 希望微软早日修复此问题, 在 NuGet 包管理中看到有更新但又不能更新的包是一件很不爽的事情!
来源: https://www.cnblogs.com/xiangxiren/p/9963709.html