一、引言
在前面文章中分別介紹了MSMQ和.NET Remoting技術,今天繼續分享.NET 平台下另一種分布式技術——Web Services
二、Web Services 詳細介紹
2.1 Web Services 概述
Web Services是支持客戶端與服務器通過網絡互操作的一種軟件系統,是一組可以通過網絡調用的應用程序API。在Web Services中主要到SOAP/UDDI/WSDL這三個核心概念,下面分別介紹下這三個概念的定義。
- SOAP:SOAP(Simple Object Access Protocol,簡單對象訪問協議)是在分散或分布式的環境中交換信息的簡單協議,是一種基於XML的協議,需要綁定一個網絡傳輸協議來完成信息的傳輸,這個協議通常是Http或Https,但也可以使其他協議。
它包括四個部分:
SOAP封裝:它定義了一個框架,描述消息中的內容是描述,是誰發送的,誰又應當接收並處理;
SOAP編碼規則:定義了一種序列化的機制,用於表示應用程序需要使用的數據類型的實例;
SOAP RPC:表示一種協定,用於表示遠程過程調用和應答;
SOAP綁定:它定義了SOAP使用哪種協議來進行交換信息。使用Http/TCP/UDP都可以。與WCF中的綁定概念一致。
換句話說,SOAP協議只是用來封裝消息用的,封裝后的消息你可以通過各種已有的協議來傳輸,如Http、Https、Tcp、UDP、SMTP等,甚至你還可以自定義協議。然而Web Service是采用基於Http協議來傳輸數據的。關於使用Https協議來訪問Web Services的方法可以參考這個文章:如何利用 SSL 調用 Web 服務。
- UDDI:是統一描述、發現和集成(Universal Description, Discovery, and Integration)的縮寫,它是一個基於XML的跨平台的描述規范,可以使世界范圍內的企業在互聯網上發布自己所提供的服務供其他客戶查詢使用。
- WSDL:是Web服務描述語言(Web Services Description Language),是為描述Web服務發布的XML格式。用於描述服務器端口訪問方式和使用協議的細節,通常用來輔助生產服務器和客戶端代碼及配置信息。
2.2 Web Services 實現過程
調用Web Services的實現過程與進行常規方法調用過程類似。不同的在於,前者方法並不位於客戶端應用程序中,而是通過指定傳輸協議生成請求消息。因為Web Services可能位於不同的計算機上,因此必須將Web Services處理請求所需的信息通過網絡傳遞給含有Web Services的服務器,Web Services在處理信息后,會通過網絡將結果發送回客戶端應用程序。下圖顯示了客戶端與Web Services之間的通信過程:
下面介紹下調用Web Services時事件發生順序:
- 在客戶端上,創建了一個Web Services代理類的實例。該對象駐留在客戶端機器上。
- 客戶端調用代理類上的方法
- 客戶端機器將Web Services方法的參數序列化為SOAP消息,然后通過傳送協議發送給Web Services。
- Web Services底層結構接收SOAP消息並進行反序列化。它會創建Web Services的類的實例,同時調用對應的Web Services方法。
- Web Services方法執行,並返回結果。
- Web Services底層結構會將返回結果序列化為SOAP消息,然后通過網絡發送回客戶端。
- 客戶端將接收SOAP消息,然后將XML反序列為返回值或任何輸出參數,並將它們傳遞給代理類的實例。
- 客戶端接收返回值和所有輸出參數。
2.3 Web Services 優缺點
經過上面詳細的介紹后,Web Services很明顯具有以下優點:
- 跨平台:Web Services完全基於XML(可擴展標記語言)、XSD(XMLSchema)等與平台無關的行業標准。
- 自描述:Web Service使用WSDL進行自我描述,包括服務的方法、參數、類型和返回值等相關信息。
- 跨防火牆:Web Service使用http協議進行通信,可以穿越防火牆。
Web Services也具有以下缺點:
- 效率低下,不適合做單應用系統的開發。
- 安全問題:Web Services沒有自身的安全機制,必須借助Http協議或IIS等宿主程序實現信息安全加密。
三、使用Web Services來開發分布式應用程序
使用Web Services來開發分布式應用較MSMQ和.NET Remoting來說相對簡單很多,今天的示例程序分三步走:
- 創建一個實現用戶信息驗證的項目WebServiceUserValidation。具體的實現代碼如下所示:
1 namespace WebServiceUserValidation 2 { 3 public class UserValidation 4 { 5 // 判斷用戶名和密碼是否有效 6 public static bool IsUserLegal(string name, string psw) 7 { 8 // 用戶可以訪問數據庫進行用戶和密碼驗證 9 // 這里僅僅作為演示 10 string password = "LearningHard"; 11 if (string.Equals(password, psw)) 12 { 13 return true; 14 } 15 else 16 { 17 return false; 18 } 19 } 20 21 // 判斷用戶的憑證是否有效 22 public static bool IsUserLegal(string token) 23 { 24 // 用戶可以訪問數據庫進行用戶憑證驗證 25 // 這里只做演示 26 string password = "LearningHard"; 27 if (string.Equals(password, token)) 28 { 29 return true; 30 } 31 else 32 { 33 return false; 34 } 35 } 36 } 37 }
2. 創建Web Services服務類,需要創建一個繼承自SoapHeader,來接收SOAP 頭里的消息,並添加WebServiceUserValidation程序集。通過添加Asp.net 空Web應用程序來創建Web Services服務工程,再右鍵創建的Web 應用程序工程添加一個Web 服務文件來創建Web 服務。具體的實現代碼如下所示:
1 // 用戶自定義的SoapHeader類必須繼承於SoapHeader 2 public class MySoapHeader : SoapHeader 3 { 4 // 存儲用戶憑證 5 public string Token { get; set; } 6 } 7 /// <summary> 8 /// LearningHardWebService 的摘要說明 9 /// </summary> 10 [WebService(Namespace = "http://www.cnblogs.com/zhili/")] 11 [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 12 [System.ComponentModel.ToolboxItem(false)] 13 // 若要允許使用 ASP.NET AJAX 從腳本中調用此 Web 服務,請取消注釋以下行。 14 // [System.Web.Script.Services.ScriptService] 15 public class LearningHardWebService : System.Web.Services.WebService 16 { 17 // 存儲用戶憑證的Soap Header信息 18 // 必須保證是public和字段名必須與SoapHeader("memberName")中memberName一樣 19 // 否則會出現“頭屬性/字段 LearningHardWebService.authenticationToken 缺失或者不是公共的。”的異常 20 public MySoapHeader authenticationToken; 21 private const string TOKEN = "LearningHard"; // 存儲服務器端憑證 22 23 24 // 定義SoapHeader傳遞的方向 25 //SoapHeaderDirection.In;只發送SoapHeader到服務端,該值是默認值 26 //SoapHeaderDirection.Out;只發送SoapHeader到客戶端 27 //SoapHeaderDirection.InOut;發送SoapHeader到服務端和客戶端 28 //SoapHeaderDirection.Fault;服務端方法異常的話,會發送異常信息到客戶端 29 [SoapHeader("authenticationToken", Direction = SoapHeaderDirection.InOut)] 30 [WebMethod(EnableSession = false)] 31 public string HelloLearningHard() 32 { 33 if (authenticationToken != null && UserValidation.IsUserLegal(authenticationToken.Token)) 34 { 35 return "LearningHard 你好,調用服務方法成功!"; 36 } 37 else 38 { 39 throw new SoapException("身份驗證失敗", SoapException.ServerFaultCode); 40 } 41 } 42 }
在上面代碼中需要注意的是,Web Servies中的Web方法需要拋出SoapExcetion異常才能被客戶端捕獲到,如果在Debug模式下調試運行的話,還需要在異常設置里把這個異常勾選掉,即編譯器不對該異常進行捕獲。
3. 創建控制台客戶端,通過添加服務引用的方式來添加Web Services,添加成功后,會在客戶端程序中創建一個代理類,客戶端可以通過該代理類來調用Web Services的方法,具體的實現代碼如下所示:
1 namespace WebServiceClient 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 // 實例化一個Soap協議的頭 8 MySoapHeader mySoapHeader = new MySoapHeader() { Token = "LearningHard"}; 9 string sResult = string.Empty; 10 LearningHardWebServiceSoapClient learningHardWebSer = null; 11 try 12 { 13 // 實例化Web服務的客戶端代理類 14 learningHardWebSer = new LearningHardWebServiceSoapClient(); 15 // 調用Web服務上的方法 16 sResult= learningHardWebSer.HelloLearningHard(ref mySoapHeader); 17 // 輸出結果 18 Console.WriteLine(sResult); 19 } 20 catch 21 { 22 Console.WriteLine("調用Web服務失敗!"); 23 } 24 finally 25 { 26 // 釋放托管資源 27 if (learningHardWebSer != null) 28 { 29 learningHardWebSer.Close(); 30 } 31 } 32 33 Console.WriteLine("請按任意鍵結束..."); 34 Console.ReadLine(); 35 } 36 } 37 }
關於Web Services異常捕獲的更多信息可以參考MSDN:在 XML Web services 中處理和引發異常。然而在這個MSDN上的示例代碼好像運行不成功,后面發現,該文章中的客戶端對異常的處理只處理了SoapException 異常,而此時客戶端觸發的異常時FaultException異常,所以異常處理代碼應像下面代碼一樣處理,當然也可以直接只處理Exception異常,我上面代碼就只處理這個大范圍的異常。
catch (SoapException ex) { // Do sth with SoapException } catch (Exception ex) { // Do sth with Exception }
經過上面的步驟,我們就已經完成了所有的開發工作,下面運行來測試下該程序的運行效果。把WebServiceClient作為啟動項目,直接按F5或Ctrl+F5來運行客戶端程序,你將看到如下所示的結果:
注:像一般分布式應用程序,都應用先運行服務器端,再運行客戶端來訪問服務方法。而這里我們運行卻直接運行客戶端就可以訪問Web Services中的Web方法了。這是因為在運行Web Services客戶端程序之前,會先把Web Services部署到IIS Express 中,你將會看到任務欄右下角有,右鍵該圖標就可以看到運行的Web Services。
四、總結
到這里,Web Services技術的分享就結束,從下一篇文章開始,將正式進入WCF的世界。而Web Services的內容和WCF內容一樣也有很多,只是微軟官方推薦采用WCF來創建Web服務程序,如果你想更多地了解Web Services的內容,可以參考MSDN:使用 ASP.NET 創建的 XML Web Services 以及 XML Web Services 客戶端
本文所有示例代碼下載:WebServiceSample