引言
最近筆者負責ERP財務系統跟中糧集團財務公司的財務系統做對接,鑒於ERP系統中應付結算單結算量比較大,而且管理相對集中,ERP系統與中糧財務公司的支付平台系統對接,實現銀企直聯,將網銀錄入的環節、付款以后ERP確認環節自動化,節省人工操作環節帶來的誤差。
這樣公司財務人員在我們的系統中做對外的付款單,自動向集團財務系統發起付款指令,由集團統一通過銀行給對應的供應商轉賬,並監控付款單的狀態,完成供應商在系統的正常結算。
系統對接環境
業務層面不再多述,本文主要介紹技術層面實施:
- 集團財務公司提供的是基於SAP架構的Web Service接口
- ERP開發環境使用VS2013
- 訪問模式是半雙工,我們ERP系統單向遠程調用接口,發起付款指令、並輪詢付款單狀態
自VS2008以后,為了對.NET Framework 3.0 或 3.5版本上WCF Service Library的支持。增加了Add Service Reference(添加服務引用)功能,這樣可以在VS中很方便的添加Web Service接口引用,並通過簡單的配置,調用遠程服務。
申請開通集團通道白名單
一般來說不可以隨便訪問集團SAP,必須找運維人員開通訪問權限。開通后,通過telnet查看ip地址和端口是否已經開放,或者瀏覽器訪問,正常的話應該如下圖:
項目中添加服務引用
選中項目,右鍵 -> Add -> Service Reference
彈出的界面中,Address輸入提供的Web Service地址,然后點擊 GO 按鈕,這里一般會提示輸入用戶名和密碼,輸入后可以看到Web Service引用連通。展開服務,可以看到接口提供了2個方法。如果這一步提示錯誤,可以在瀏覽器中輸入地址,看看是否能訪問,其實就是訪問遠程的wsdl文件,如果訪問不了,再檢查是否是網絡或者權限的原因。
我們點“確定”,可以看到VS自動幫我們在項目目錄下生成了一個文件夾:Service References,里面有剛才看到的服務名,同時會在 app.config 中增加一段配置類似如下(如果當前沒有app.config文件,會自動生成):
<system.serviceModel>
<client>
<endpoint address="http://xx.xx.xxx.xx:50000/xxxxxxx"
binding="basicHttpBinding" bindingConfiguration="SOS_TxService_SendBinding"
contract="TxService.SOS_TxService_Send" name="HTTP_Port" />
</client>
</system.serviceModel>
VS幫我們做了什么
為了更好的學習,我們深入了解一下,VS幫我們都做了哪些工作。
項目新建的Service References目錄下的服務,在VS中是無法查看的,我們可以進入對應的目錄下,看看都生成了哪些文件:
首先可以看到,目錄下有個wsdl文件,大家應該都熟悉,這是用來定義和描述Web Service的,通過這個文件,就可以知道接口都提供了哪些方法,輸入參數類型和輸出結果格式。打開這個wsdl文件看一下,跟我們想象的一樣,原來,VS在引用服務訪問遠程wsdl文件的同時,在本地拷貝了一份。
接下來我們看一個后綴為 .cs 重要的文件,打開看下,這里面,VS幫我們生成了關於這個服務的接口和實現類。
這里最重要的,是幫我們生成了 SOS_TxService_SendClient 這個類,研究一下,發現已經實現了之前看到的Send、Send1兩個方法,並提供了對應的異步方法。
我們整理一下VS做的工作:
- 添加服務引用時,訪問遠程 wsdl 文件,並拷貝本地;
- 根據 wsdl 文件中的接口定義,定義調用端接口(比如Send,Send1);
- 定義代理服務 SendClient 類,繼承上述定義的調用端接口,並提供具體實現(實現Send,Send1);
- 定義和實現其他輔助類,比如 SendRequest,SendResponse;
- 生成 app.config 中相關配置;
到這里,聰明的你可能要問,既然VS已經幫我們生成了代理服務類 SendClient,而且類已經提供了接口方法的具體實現,現在是不是直接實例化一個服務類,直接調用方法就可以遠程調用?是的,沒錯!VS基本把需要做的工作都幫你做了,剩下的就是使用就行了,簡單吧。
其他相關配置
一般情況下,我們訪問Web Service,需要提供用戶名和密碼的權限認證,否則直接調用的話,會報錯。
這里我們修改一下 app.config 文件如下:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="SOS_TxService_SendBinding" >
<security mode="TransportCredentialOnly" >
<transport clientCredentialType="Basic"/>
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://xx.xx.xxx.xx:50000/xxxxxxx"
binding="basicHttpBinding" bindingConfiguration="SOS_TxService_SendBinding"
contract="TxService.SOS_TxService_Send" name="HTTP_Port" />
</client>
</system.serviceModel>
單元測試調用一下,可以看到能正常返回 xml 格式的結果:
[TestMethod]
public void WebServiceTest()
{
var client = new SOS_TxService_SendClient();
if (client.ClientCredentials != null)
{
client.ClientCredentials.UserName.UserName = "username";
client.ClientCredentials.UserName.Password = "password";
try
{
var tt = client.Send("test");
Assert.IsTrue(tt.Length > 0);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
}
還有一個問題,就是跨項目引用,比如在一個基礎服務項目中,實現了遠程調用。在應用層項目中,引用了基礎服務項目dll,應該注意以下一點:選中生成的服務,右鍵-> Configure Service Reference:
保證相關的程序集能夠正常引用,然后在應用層項目,並手動將 app.config 的相關配置拷貝至項目目錄下。
寫在最后
至此,我們通過VS調用 Web Service 實施成功,還是比較簡單,其實沒有什么技術難點,主要希望能深入了解原理,知道VS后台自動幫助我們做了哪些工作,如果我們不使用輔助工具的時候,要實現遠程訪問,應該怎么去實現。
注:目前 .net core 環境對 Web Service 支持不是很好,筆者在VS2017中,.net core 引用 Web Service依舊報錯,大家有興趣可以自己研究一下。