記一次.net core呼叫SOAP介面遇到的問題
背景
最近需要將一些外部的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包管理中看到有更新但又不能更新的包是一件很不爽的事情!