認識WCF

WCF

1、什麼是WCF?html

一、Windows Communication Foundation(WCF)是由微軟發展的一組數據通訊的應用程序開發接口,能夠翻譯爲Windows通信接口。它是.NET框架的一部分,由 .NET Framework[1] 3.0 開始引入,與 Windows Presentation Foundation及 Windows Workflow Foundation並行爲新一代 Windows 操做系統以及 WinFX 的三個重大應用程序開發類庫。web

二、好久之前,有一家小商店,靠賣些水果過日子。競爭是如此激烈,爲了生存,他們不得不本身進貨,把貨堆到本身的房間內,若是顧客須要,他們有時還不得不給顧客送貨,總而言之,他們將全部該乾的活都幹了,只爲了能賺到點生活費,這就是艱辛的人生。

一個web程序或者一個winform程序,簡單模式的程序,咱們一般都如那個水果店的老闆同樣,把全部的功能都集中到這個程序裏,在簡單的情況下,這很好。

水果店生意愈來愈好,老闆的資金慢慢雄厚了,他注意到了賣其餘東西比賣水果更賺錢,好比說家電、服裝。因而,老闆一口氣又開了幾家店。生意規模愈來愈大,錢也越賺越多,老闆心花盛開。然而好景不長,亞洲金融風暴來襲,利潤率急劇降低。老闆憂心忡忡,既然外部開源不太可能,那就看看內部能不能節流了。老闆考察一番,注意到,爲了銷售,每一個店都配置了一個倉庫,每一個店都配置了一幫送貨的人馬,這,是否是太浪費了。因而,老闆將全部的倉庫撤銷,成立了一個總倉庫,不論是水果,家店,服裝,均可以存儲到這個倉庫。管理一個倉庫的費用比管理N個倉庫的費用顯然是要少不少的。而後,每一個店的送貨人員都辭掉,另外成立一個運輸公司,專門負責送貨,不過水果仍是家店仍是服裝,裝到紙箱後,他們都是一個樣。通過這麼一折騰,成本一下就降了下來,並且還便於管理了,真是一箭雙鵰,老闆又綻開了笑容。

當程序涉及的範圍愈來愈大時,也許就要考慮將服務分離出去。WCF是應對分佈式開發的,就如水果店老闆,生意大了後,他就是個分佈式的了,這邊一家水果店,那邊一家服裝店,他們之間有區別,賣的東西不一樣,也有共性,都是賣東西,不論是哪家店,他們都須要倉庫,都須要送貨。這時,你就能夠單獨成立公司,只提供這兩種服務。若是寫成程序,那麼就如同你開發了一個運輸的WCF,把這個服務放在服務器上,這樣不論是誰,是Web程序也好,是Winform程序也好,只要接口對應,理解你的服務內容條款(服務契約),均可以要求你這個服務模塊提供標準的服務。(來源於http://zhidao.baidu.com/question/148197639.html)

三、WCF 是一個分佈式應用的開發框架,屬於特定的技術,或者平臺。既不是標準也不是規範。
Web Service:嚴格來講是行業標準,也就是Web Service 規範,也稱做WS-*規範,既不是框架,也不是技術。

四、Visual Studio 2008及之後的版本纔有wcf的功能。

2、怎麼使用WCF?

1、定義服務契約

在這個實例中,咱們建立一個簡單的服務來管理員工的基本信息。至於實例程序的結構,咱們依然採用熟悉的包含三個項目(Service.Interface、Service和Client)的解決方案。以下所示的是定義在Service.Interface中用於表示員工的Employee類的定義,它是一個數據契約。編程

   1: [DataContract(Namespace="http://www.artech.com/")]
   2: public class Employee
   3: {
   4:     [DataMember]
   5:     public string Id { get; set; }
   6:  
   7:     [DataMember]
   8:     public string Name { get; set; }
   9:  
  10:     [DataMember]
  11:     public string Department { get; set; }
  12:  
  13:     [DataMember]
  14:     public string Grade { get; set; }
  15:  
  16:     public override string ToString()
  17:     {
  18:         return string.Format("ID: {0,-5}姓名: {1, -5}級別: {2, -4} 部門: {3}",Id, Name, Grade, Department);
  19:     }
  20: }

接下來咱們定義了以下一個表示服務契約的接口IEmployeesService。和基於SOAP的服務契約定義不一樣,咱們無需在相應的操做方法上面應用OperationContractAttribute特性,可是應用在接口/類上的ServiceContractAttribute特性還是必需的。在這裏替換OperationContractAttribute特性的分別是WebGetAttributeWebInvokeAttribute,它們均定義在System.ServiceModel.Web程序集中。瀏覽器

   1: [ServiceContract(Namespace="http://www.artech.com/")]
   2: public interface IEmployees
   3: {
   4:     [WebGet(UriTemplate = "all")]
   5:     IEnumerable<Employee> GetAll();
   6:  
   7:     [WebGet(UriTemplate = "{id}")]
   8:     Employee Get(string id);
   9:  
  10:     [WebInvoke(UriTemplate = "/", Method = "POST")]
  11:     void Create(Employee employee);
  12:  
  13:     [WebInvoke(UriTemplate = "/", Method = "PUT")]
  14:     void Update(Employee employee);
  15:  
  16:     [WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
  17:     void Delete(string id);
  18: }

契約接口IEmployeesService中定義了5個操做,分別用於實現針對員工數據的獲取、添加、修改和刪除。按照REST設計原則,咱們將被操做的員工信息體現爲某種網絡資源,而操做類型最好與相應的HTTP方法相匹配。在操做方法中針對資源的操做類型與HTTP方法之間的匹配是經過應用在它們上面的WebGetAttribute和WebInvokeAttribute特性來體現。服務器

WebGetAttribute針對GET方法,而其餘的HTTP方法則經過WebInvokeAttribute的Method屬性來體現。在IEmployeesService中,兩個用於獲取員工信息GetAll和Get方法均應用了WebGetAttribute特性,而其餘的Create、Update和Delete方法在應用了WebInvokeAttribute特性,而且其Method屬性被分別設置爲PUT、POST和DELETE。網絡

WebGetAttribute和WebInvokeAttribute和均具備相同的屬性UriTemplate,該屬性用於定義做爲最終操做URI的模板。咱們不只能夠經過UriTemplate屬性爲操做指定一個相對於終結點地址的靜態路徑,還能夠經過佔位符實現路徑中的動態部分與參數之間的映射。app

一樣以定義在契約接口IEmployeesService中的5個操做方法爲例,若是終結點地址爲http://127.0.0.1:3721/employees,因爲用於返回全部員工列表的GetAll操做的UriTemplate被設置「All」,因此其地址爲http://127.0.0.1:3721/employees。用於返回指定員工ID的Get操做的UriTemplate被設置成「{id}」,意味着咱們直接在表示請求地址的URI中指定員工的ID,而它會自動映射爲該操做方法的參數id。用於刪除某個指定員工的Delete操做具備相同的UriTemplate設置,而用於建立添加新員工和修改現有員工信息的Create和Update操做,因爲做爲參數的Employee對象具備ID屬性,因此直接採用終結點地址。框架

2、建立/寄宿服務

在控制檯程序Service中咱們定義了以下一個實現了契約接口IEmployeesService的服務類型EmployeesService。簡單 起見,咱們直接經過一個靜態字段employees表示存儲的員工列表,該靜態字段在初始化的工做中被添加了兩個ID分別爲001和002的Employee對象。針對員工信息的獲取、添加、修改和刪除的操做均在此列表中進行。分佈式

   1: public class EmployeesService : IEmployees
   2: {
   3:     private static IList<Employee> employees = new List<Employee>
   4:     {
   5:         new Employee{ Id = "001", Name="張三", Department="開發部", Grade = "G7"},    
   6:         new Employee{ Id = "002", Name="李四", Department="人事部", Grade = "G6"}
   7:     };
   8:     public Employee Get(string id)
   9:     {
  10:         Employee employee = employees.FirstOrDefault(e => e.Id == id);
  11:         if (null == employee)
  12:         {
  13:             WebOperationContext.Current.OutgoingResponse.StatusCode = 
  14:             HttpStatusCode.NotFound;
  15:         }
  16:         return employee;
  17:     }
  18:  
  19:     public void Create(Employee employee)
  20:     {
  21:         employees.Add(employee);
  22:     }
  23:  
  24:     public void Update(Employee employee)
  25:     {
  26:         this.Delete(employee.Id);
  27:         employees.Add(employee);
  28:     }
  29:  
  30:     public void Delete(string id)
  31:     {
  32:         Employee employee = this.Get(id);
  33:         if (null != employee)
  34:         {
  35:             employees.Remove(employee);
  36:         }
  37:     }
  38:  
  39:     public IEnumerable<Employee> GetAll()
  40:     {
  41:         return employees;
  42:     }
  43: }

值得一提的是,不管是用於獲取某個指定ID的員工信息的Get方法,仍是用於修改和刪除員工記錄的Update和Delete方法,當指定ID的員工不存在時都經過WebOperationContext表示當前Web操做上下文的對象將回復狀態設置爲NotFound(即404 Not Found),這體現了咱們的服務是基於Web的。ide

接下來咱們經過自我寄宿的方式對上面定義的EmployeesService服務進行寄宿,下面是相應的配置。咱們爲寄宿的服務添加了惟一一個終結點,並簡單地指定了其ABC三要素。和咱們以前配置的終結點不一樣的是,在這裏咱們採用的綁定類型爲WebHttpBinding。

   1: <configuration>
   2:     <system.serviceModel>
   3:     <services>
   4:         <service name="Artech.WcfServices.Service.EmployeesService">
   5:         <endpoint address="http://127.0.0.1:3721/employees" 
   6:                   binding="webHttpBinding"
   7:                   contract="Artech.WcfServices.Service.Interface.IEmployees"/>
   8:         </service>
   9:     </services>
  10:     </system.serviceModel>
  11: </configuration>

最終咱們經過以下的程序進行服務的寄宿。以前咱們老是使用基於服務類型建立的ServiceHost進行服務寄宿,在這裏咱們使用的是ServiceHost它的子類WebServiceHost

   1: using (WebServiceHost host = new WebServiceHost(typeof(EmployeesService)))
   2: {
   3:     host.Open();
   4:     Console.Read();
   5: }
 
 

3、進行服務調用

因爲咱們寄宿的服務徹底是基於Web的,因此和普通的Web站點沒有本質的區別。因爲EmployeesService服務的GetAll和Get操做支持HTTP-GET請求,因此咱們徹底能夠在瀏覽器中針對操做的地址發起請求,而返回的數據能夠直接顯示在瀏覽器上。下圖所示的是經過瀏覽器調用GetAll操做(http://127.0.0.1:3721/employees/all)獲得的結果,咱們能夠看到全部員工的列表以XML的形式返回。

image

咱們也能夠經過瀏覽器調用Get操做並直接經過在地址中指定員工的ID(http://127.0.0.1:3721/employees/001)並獲得以XML表示的基於相應員工的信息。下圖所示XML正式ID爲001的Employee對象序列化後的結果。若是在請求地址中指定一個不存在的ID(好比http://127.0.0.1:3721/employees/003),因爲Get方法中指定了回覆狀態爲NotFound,咱們會獲得相似於訪問資源不存在的錯誤信息,就像訪問一個不存在的Web頁面同樣。

image

上面咱們演示了經過瀏覽器以HTTP-GET方式請求操做地址的方式從而直接將返回結果呈現出來,如今咱們來演示如何使用經過ChannelFactory<TChannel>建立的服務代理進行服務調用。咱們首先在做爲客戶端應用程序的Client項目中建立一個App.config,並定義以下的配置。

   1: <configuration>
   2:   <system.serviceModel>
   3:     <behaviors>
   4:       <endpointBehaviors>
   5:         <behavior name="webBehavior">
   6:           <webHttp />
   7:         </behavior>
   8:       </endpointBehaviors>      
   9:     </behaviors>
  10:     <client>
  11:       <endpoint name="employeeService"
  12:         address="http://127.0.0.1:3721/employees" 
  13:         behaviorConfiguration="webBehavior"
  14:         binding="webHttpBinding" 
  15:         contract="Artech.WcfServices.Service.Interface.IEmployees"/>
  16:     </client>
  17:   </system.serviceModel>
  18: </configuration>

如上面的配置片段所示,咱們定義了一個與服務端相匹配的客戶端終結點,該終結點上應用了一個WebHttpBehavior終結點行爲。WebHttpBehavior能夠說是整個Web HTTP編程模型的核心,絕大部分針對Web的支持都是經過該行爲實現的。實際上服務端終結點經過WebServiceHost應用了這個終結點行爲。

   1: using(ChannelFactory<IEmployees> channelFactory = new ChannelFactory<IEmployees>("employeeService"))
   2: {
   3:     IEmployees proxy = channelFactory.CreateChannel();
   4:  
   5:     Console.WriteLine("全部員工列表:");
   6:     Array.ForEach<Employee>(proxy.GetAll().ToArray(),employee=>Console.WriteLine(employee));
   7:  
   8:     Console.WriteLine("\n添加一個新員工(003):");
   9:     proxy.Create(new Employee
  10:     {
  11:         Id              = "003",
  12:         Name            = "王五",
  13:         Grade           = "G9",
  14:         Department      = "行政部"
  15:     });
  16:     Array.ForEach<Employee>(proxy.GetAll().ToArray(),employee => Console.WriteLine(employee));
  17:  
  18:     Console.WriteLine("\n修改員工(003)信息:");
  19:     proxy.Update(new Employee
  20:     {
  21:         Id              = "003",
  22:         Name            = "王五",
  23:         Grade           = "G11",
  24:         Department      = "銷售部"
  25:     });
  26:     Array.ForEach<Employee>(proxy.GetAll().ToArray(), employee => Console.WriteLine(employee));
  27:     Console.WriteLine("\n刪除員工(003)信息:");
  28:  
  29:     proxy.Delete("003");
  30:     Array.ForEach<Employee>(proxy.GetAll().ToArray(), employee => Console.WriteLine(employee));        
  31: }

服務調用程序如上所示,咱們模擬了員工的添加、修改和刪除。程序以後會在客戶端控制檯產生以下的輸出。

全部員工列表:

   1: 全部員工列表:
   2: ID: 001  姓名: 張三   級別: G7   部門: 開發部
   3: ID: 002  姓名: 李四   級別: G6   部門: 人事部
   4:  
   5: 添加一個新員工(003):
   6: ID: 001  姓名: 張三   級別: G7   部門: 開發部
   7: ID: 002  姓名: 李四   級別: G6   部門: 人事部
   8: ID: 003  姓名: 王五   級別: G9   部門: 行政部
   9:  
  10: 修改員工(003)信息:
  11: ID: 001  姓名: 張三   級別: G7   部門: 開發部
  12: ID: 002  姓名: 李四   級別: G6   部門: 人事部
  13: ID: 003  姓名: 王五   級別: G11  部門: 銷售部
  14:  
  15: 刪除員工(003)信息:
  16: ID: 001  姓名: 張三   級別: G7   部門: 開發部
  17: ID: 002  姓名: 李四   級別: G6   部門: 人事部

從編程角度來看,咱們採用與SOAP服務徹底同樣的服務調用方式,那麼如何反映出服務調用基於Web的本質呢?首先,以前咱們可以經過瀏覽器訪問GetAll和Get兩個操做能夠證實這兩個服務操做是基於HTTP-GET的,返回的數據直接以單純的XML返回,並無封裝成SOAP。爲了證實Create、Update和Delete也是徹底基於Web的,咱們能夠經過Fiddler來分析HTTP請求的內容。

以下所示的三段XML片段分別對應着針對上述三個服務操做調用的HTTP請求消息,從這咱們能夠看出它們就是單純的針對PUT、POST和DELETE方法的HTTP請求,而傳輸給服務端的數據直接做爲消息的主體,並無封裝成SOAP消息。

   1: Create:
   2: PUT http://jinnan-pc:3721/employees/ HTTP/1.1
   3: Content-Type: application/xml; charset=utf-8
   4: Host: jinnan-pc:3721
   5: Content-Length: 187
   6: Expect: 100-continue
   7: Accept-Encoding: gzip, deflate
   8:  
   9: <Employee xmlns="http://www.artech.com/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Department>銷售部</Department><Grade>G11</Grade><Id>003</Id><Name>王五</Name></Employee>
  10:  
  11: Update:
  12: POST http://jinnan-pc:3721/employees/ HTTP/1.1
  13: Content-Type: application/xml; charset=utf-8
  14: Host: jinnan-pc:3721
  15: Content-Length: 186
  16: Expect: 100-continue
  17: Accept-Encoding: gzip, deflate
  18:  
  19: <Employee xmlns="http://www.artech.com/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Department>行政部</Department><Grade>G9</Grade><Id>003</Id><Name>王五</Name></Employee>
  20:  
  21: Delete:
  22: DELETE http://jinnan-pc:3721/employees/003 HTTP/1.1
  23: Content-Type: application/xml; charset=utf-8
  24: Host: jinnan-pc:3721
  25: Content-Length: 80
  26: Expect: 100-continue
  27: Accept-Encoding: gzip, deflate(來源於http://www.cnblogs.com/artech/archive/2012/02/04/wcf-rest-sample.html)
相關文章
相關標籤/搜索