記一次.net core呼叫SOAP介面遇到的問題
背景
最近需要將一些外部的 Web Service
及其他 SOAP
介面的呼叫移到一個獨立的 WebAPI
專案中,然後供其他 .Net Core
專案呼叫。之前的幾個 Web Service
已經成功遷移,但是在遷移一個需要使用者名稱密碼認證的 SOAP/">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
的時候找到一些相關東西,特別是這一條 ofollow,noindex" target="_blank">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包管理中看到有更新但又不能更新的包是一件很不爽的事情!