本文的WCF服務應用功能很簡單,卻涵蓋了一個完整WCF應用的基本結構。希望本文能對那些準備開始學習WCF的初學者提供一些幫助。 在這個例子中,我們將實現一個簡單的計算器和傳統的分散式通信框架一樣,WCF本質上提供一個跨進程、跨機器、跨網路的服務調用。在本例中,客戶端和WCF應用服務通過運行在同一臺機 ...
本文的WCF服務應用功能很簡單,卻涵蓋了一個完整WCF應用的基本結構。希望本文能對那些準備開始學習WCF的初學者提供一些幫助。
在這個例子中,我們將實現一個簡單的計算器和傳統的分散式通信框架一樣,WCF本質上提供一個跨進程、跨機器、跨網路的服務調用。在本例中,客戶端和WCF應用服務通過運行在同一臺機器上的不同進程模擬。
步驟一、構建整個解決方案
1.創建一個空白的解決方案
2.添加四個項目和引用及關係
Service.Interface 用於定義服務契約的類庫項目,引用WCF核心程式集System.ServuceModel.dll
Service 用於定義服務類型的類庫項目,由於服務類型需要實現定義在ervice.Interface中相應的介面,因此需要引用Service.Interface
Hosting 作為服務寄主的控制台應用,該項目同時引用Service.Interface、System.ServuceModel.dll、Service
Client 模擬服務的客服端控制台應用 該醒目引用System.ServuceModel.dll
步驟二、創建服務契約(一般將服務契約定義為介面)
WCF採用基於介面(MSDN上翻譯為:服務協定)的交互方式實現了服務功能,以及客戶端和服務端之間的松耦合。WCF包含五種類型的協定:服務協定、操作協定、消息協定、錯誤協定和數據協定。
從功能上講,服務協定將多個相關的操作聯繫在一起,組成單個功能單元。協定可以定義服務級設置,如服務的命名空間、對應的回調協定以及其他此類設置,以及各種操作。
從消息交換的角度來講,服務協定則定義了基於服務調用的消息交換過程中, 請求消息和回覆消息的結構,以及採用的消息交換模式。
從使用編程語言的角度來講,協定是通過所選的編程語言創建一個介面,然後將 ServiceContractAttribute 屬性應用於該介面。通過實現該介面,可生成實際的服務代碼。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.ServiceModel; 7 8 namespace Service.Interface 9 { 10 /// <summary> 11 /// 計算器 12 /// </summary> 13 [ServiceContract(Name = "CalculatorService",Namespace="http://www.artech.com/")] 14 public interface ICalculator 15 { 16 /// <summary> 17 /// 加 18 /// </summary> 19 /// <param name="x"></param> 20 /// <param name="y"></param> 21 /// <returns></returns> 22 [OperationContract] 23 double Add(double x,double y); 24 25 /// <summary> 26 /// 減 27 /// </summary> 28 /// <param name="x"></param> 29 /// <param name="y"></param> 30 /// <returns></returns> 31 [OperationContract] 32 double Subtract(double x,double y); 33 34 /// <summary> 35 /// 乘 36 /// </summary> 37 /// <param name="x"></param> 38 /// <param name="y"></param> 39 /// <returns></returns> 40 [OperationContract] 41 double Multiply(double x,double y); 42 43 /// <summary> 44 /// 除 45 /// </summary> 46 /// <param name="x"></param> 47 /// <param name="y"></param> 48 /// <returns></returns> 49 [OperationContract] 50 double Divide(double x,double y); 51 } 52 }
步驟三、實現WCF服務契約
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using Service.Interface; 7 8 namespace Service 9 { 10 public class CalculatorService:ICalculator 11 { 12 13 14 public double Add(double x, double y) 15 { 16 return x + y; 17 } 18 19 public double Subtract(double x, double y) 20 { 21 return x - y; 22 } 23 24 public double Multiply(double x, double y) 25 { 26 return x * y; 27 } 28 29 public double Divide(double x, double y) 30 { 31 return x / y; 32 } 33 } 34 }
步驟四、通過自我寄宿的方式寄宿服務
WCF服務需要依存一個運行著的進程(宿主),服務寄宿就是為服務指定一個宿主的過程。WCF是一個基於消息的通信框架,採用基於終結點(Endpoint)的通信手段。
終結點主要由地址(Address)、綁定(Binding)和協定(Contract)三要素組成,如圖所示。由於三要素應為首字母分別為ABC,所以就有了易於記憶的公式:Endpoint = ABC。一個終結包含了實現通信所必需的所有信息。如下圖。
終結點三要素
- 地址(Address):一個指示可以查找終結點的位置的地址。地址決定了服務的位置,解決了服務定址的問題
- 綁定(Binding):一個指定客戶端如何與終結點進行通信的綁定。綁定實現了通信的所有細節,包括網路傳輸、消息編碼,以及其他為實現某種功能(比如安全、可靠傳輸、事務等)對消息進行的相應處理。WCF中具有一系列的系統定義綁定,比如BasicHttpBinding、WsHttpBinding、NetTcpBinding等,
- 協定(Contract):一個標識可用操作的協定。協定是對服務操作的抽象,也是對消息交換模式以及消息結構的定義。
- 行為(Behavior):一組指定終結點的本地實現細節的行為。
服務寄宿的目的就是開啟一個進程,為WCF服務應用提供一個運行的環境。通過為服務添加一個或多個終結點,使之暴露給潛在的服務調用者。服務調用者最終通過相匹配的終結點對該服務進行調用。
一)代碼方式實現寄宿
1 using Service; 2 using Service.Interface; 3 using System.ServiceModel; 4 using System.ServiceModel.Description; 5 6 namespace Hosting 7 { 8 class Program 9 { 10 static void Main(string[] args) 11 { 12 //在進行真正的開放時一般在配置文件裡面進行配置添加終結點和服務行為的定義 13 using(ServiceHost host = new ServiceHost(typeof(CalculatorService))) 14 { 15 //指定綁定和總結點的地址 16 host.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "http://127.0.0.1:3721/calculatorservice"); 17 //數據的發佈 18 if(host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null) 19 { 20 //創建服務行為 21 ServiceMetadataBehavior behavior = new ServiceMetadataBehavior(); 22 //是否發佈元數據以便使用HTTPS/GET請求進行檢索 23 behavior.HttpGetEnabled = true; 24 //使用HTTPS/GET請求的元數據發佈的位置 25 behavior.HttpGetUrl = new Uri("http://127.0.0.1:3721/calculatorservice/metadata"); 26 //添加到發佈上 27 host.Description.Behaviors.Add(behavior); 28 } 29 host.Opened += delegate 30 { 31 Console.WriteLine("CalculatorService已經啟動,按任意鍵終止服務!"); 32 }; 33 //通訊狀態轉換到已打開 34 host.Open(); 35 Console.ReadLine(); 36 } 37 } 38 } 39 }
1) WCF服務寄宿通過一個特殊的對象完成:ServiceHost。在上面的代碼基本實現的功能說明,基於WCF服務應用的類型(typeof(CalculatorService))創建了ServieHost對象,並添加了一個終結點。具體的地址為http://127.0.0.1:3721/calculatorservice/metadata,採用了WSHttpBinding,並指定了服務協定的類型ICalculator。
2) 松耦合是SOA的一個基本的特征,WCF服務應用中客戶端和服務端的松耦合體現在客戶端只需要瞭解WCF服務基本的描述,而無需知道具體的實現細節,就可以實現正常的WCF服務調用。WCF服務的描述通過元數據(Metadata)的形式發佈出來。WCF中元數據的發佈通過一個特殊的服務行為ServiceMetadataBehavior實現。在上面提供的服務寄宿代碼中,我們為創建的ServiceHost添加了ServiceMetadataBehavior,並採用了基於HTTP-GET的元數據獲取方式,元數據的發佈地址通過ServiceMetadataBehavior的HttpGetUrl指定。在調用ServiceHost的Open方法對服務成功寄宿後,我們可以通過該地址獲取服務相關的元數據。
3) 運行已經生成的hosting.exe,
4)然後在瀏覽器地址欄上鍵入http://127.0.0.1:3721/calculatorservice/metadata,你將會得到以WSDL形式體現的服務元數據,如下圖所示。
二)配置文件方式實現寄宿
在實際應用中,對於WCF應用服務的寄宿,一般不會直接通過編碼的方式進行終結點的添加和服務行為的定義,而是通過寫配置文件的方式實現,這樣可以方便修改。
1) 現在我在Hosting項目中添加一個app.config配置文件,把下麵的配置信息添加到配置文件app.config中。
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <startup> 4 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> 5 </startup> 6 <system.serviceModel> 7 8 <behaviors> 9 <serviceBehaviors> 10 <behavior name="metadataBehavior"> 11 <serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:3721/calculatorservice/metadata" /> 12 </behavior> 13 </serviceBehaviors> 14 </behaviors> 15 16 <services> 17 <service behaviorConfiguration="metadataBehavior" name="Service.CalculatorService"> 18 <endpoint address="http://127.0.0.1:3721/calculatorservice" 19 binding="wsHttpBinding" bindingConfiguration="" contract="Service.Interface.ICalculator" /> 20 </service> 21 </services> 22 23 </system.serviceModel> 24 </configuration>
2) 增加app.config配置文件與配置信息之後,我們原來寫的寄宿代碼就不能使用了,需要進行服務寄宿代碼的修改,而且代碼會變的更簡潔,只需幾行代碼就可以了。代碼如下。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using Service; 7 using Service.Interface; 8 using System.ServiceModel; 9 using System.ServiceModel.Description; 10 11 namespace Hosting 12 { 13 class Program 14 { 15 static void Main(string[] args) 16 { 17 using(ServiceHost host = new ServiceHost(typeof(CalculatorService))) 18 { 19 ////指定綁定和終結點的地址 20 //host.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "http://127.0.0.1:3721/calculatorService"); 21 ////數據的發佈 22 //if(host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null) 23 //{ 24 // //創建服務行為 25 // ServiceMetadataBehavior behavior = new ServiceMetadataBehavior(); 26 // //是否發佈元數據以便使用HTTPS/GET請求進行檢索 27 // behavior.HttpGetEnabled = true; 28 // //使用HTTPS/GET請求的元數據發佈的位置 29 // behavior.HttpGetUrl = new Uri("http://127.0.0.1:3721/calculatorService/metadata"); 30 // //添加到發佈上 31 // host.Description.Behaviors.Add(behavior); 32 //} 33 host.Opened += delegate 34 { 35 Console.WriteLine("CalculatorService已經啟動,按任意鍵終止服務!"); 36 }; 37 //通訊狀態轉換到已打開 38 host.Open(); 39 Console.ReadLine(); 40 } 41 } 42 } 43 }
3) 執行hosting.exe應用程式,結果如下圖。
下一章節講怎麼通過客戶端去調用我們成功寄宿後的服務 (歡迎關註)