背景
最近需要将一些外部的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.ServiceModel
4.5.0及以上版本会存在此问题,降级到4.4.4方可解决,希望微软早日修复此问题,在NuGet包管理中看到有更新但又不能更新的包是一件很不爽的事情!