背景
最近需要將一些外部的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包管理中看到有更新但又不能更新的包是一件很不爽的事情!
