认识WCF
WCF
一、什么是WCF?
1、Windows Communication Foundation(WCF)是由微軟發(fā)展的一組數(shù)據(jù)通信的應(yīng)用程序開發(fā)接口,可以翻譯為Windows通訊接口。它是.NET框架的一部分,由 .NET Framework[1]?3.0 開始引入,與 Windows Presentation Foundation及 Windows Workflow Foundation并行為新一代 Windows?操作系統(tǒng)以及 WinFX 的三個(gè)重大應(yīng)用程序開發(fā)類庫。
2、很久以前,有一家小商店,靠賣些水果過日子。競(jìng)爭是如此激烈,為了生存,他們不得不自己進(jìn)貨,把貨堆到自己的房間內(nèi),如果顧客需要,他們有時(shí)還不得不給顧客送貨,總而言之,他們將所有該干的活都干了,只為了能賺到點(diǎn)生活費(fèi),這就是艱辛的人生。一個(gè)web程序或者一個(gè)winform程序,簡單模式的程序,我們通常都如那個(gè)水果店的老板一樣,把所有的功能都集中到這個(gè)程序里,在簡單的狀況下,這很好。
水果店生意越來越好,老板的資金慢慢雄厚了,他注意到了賣其他東西比賣水果更賺錢,比如說家電、服裝。于是,老板一口氣又開了幾家店。生意規(guī)模越來越大,錢也越賺越多,老板心花怒放。然而好景不長,亞洲金融風(fēng)暴來襲,利潤率急劇下降。老板憂心忡忡,既然外部開源不太可能,那就看看內(nèi)部能不能節(jié)流了。老板考察一番,注意到,為了銷售,每個(gè)店都配置了一個(gè)倉庫,每個(gè)店都配置了一幫送貨的人馬,這,是不是太浪費(fèi)了。于是,老板將所有的倉庫撤銷,成立了一個(gè)總倉庫,不管是水果,家店,服裝,都可以存儲(chǔ)到這個(gè)倉庫。管理一個(gè)倉庫的費(fèi)用比管理N個(gè)倉庫的費(fèi)用顯然是要少很多的。然后,每個(gè)店的送貨人員都辭掉,另外成立一個(gè)運(yùn)輸公司,專門負(fù)責(zé)送貨,不過水果還是家店還是服裝,裝到紙箱后,他們都是一個(gè)樣。經(jīng)過這么一折騰,成本一下就降了下來,而且還便于管理了,真是一舉兩得,老板又綻放了笑容。
當(dāng)程序涉及的范圍越來越大時(shí),也許就要考慮將服務(wù)分離出去。WCF是應(yīng)對(duì)分布式開發(fā)的,就如水果店老板,生意大了后,他就是個(gè)分布式的了,這邊一家水果店,那邊一家服裝店,他們之間有區(qū)別,賣的東西不同,也有共性,都是賣東西,不管是哪家店,他們都需要倉庫,都需要送貨。這時(shí),你就可以單獨(dú)成立公司,只提供這兩種服務(wù)。如果寫成程序,那么就如同你開發(fā)了一個(gè)運(yùn)輸?shù)腤CF,把這個(gè)服務(wù)放在服務(wù)器上,這樣不管是誰,是Web程序也好,是Winform程序也好,只要接口對(duì)應(yīng),理解你的服務(wù)內(nèi)容條款(服務(wù)契約),都可以要求你這個(gè)服務(wù)模塊提供標(biāo)準(zhǔn)的服務(wù)。(來源于http://zhidao.baidu.com/question/148197639.html)
3、WCF 是一個(gè)分布式應(yīng)用的開發(fā)框架,屬于特定的技術(shù),或者平臺(tái)。既不是標(biāo)準(zhǔn)也不是規(guī)范。
Web Service:嚴(yán)格來說是行業(yè)標(biāo)準(zhǔn),也就是Web Service 規(guī)范,也稱作WS-*規(guī)范,既不是框架,也不是技術(shù)。
4、Visual Studio 2008及以后的版本才有wcf的功能。
二、怎么使用WCF?
一、定義服務(wù)契約
在這個(gè)實(shí)例中,我們創(chuàng)建一個(gè)簡單的服務(wù)來管理員工的基本信息。至于實(shí)例程序的結(jié)構(gòu),我們依然采用熟悉的包含三個(gè)項(xiàng)目(Service.Interface、Service和Client)的解決方案。如下所示的是定義在Service.Interface中用于表示員工的Employee類的定義,它是一個(gè)數(shù)據(jù)契約。
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}級(jí)別: {2, -4} 部門: {3}",Id, Name, Grade, Department); 19: } 20: }接下來我們定義了如下一個(gè)表示服務(wù)契約的接口IEmployeesService。和基于SOAP的服務(wù)契約定義不同,我們無需在相應(yīng)的操作方法上面應(yīng)用OperationContractAttribute特性,但是應(yīng)用在接口/類上的ServiceContractAttribute特性仍是必需的。在這里替換OperationContractAttribute特性的分別是WebGetAttribute和WebInvokeAttribute,它們均定義在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個(gè)操作,分別用于實(shí)現(xiàn)針對(duì)員工數(shù)據(jù)的獲取、添加、修改和刪除。按照REST設(shè)計(jì)原則,我們將被操作的員工信息體現(xiàn)為某種網(wǎng)絡(luò)資源,而操作類型最好與相應(yīng)的HTTP方法相匹配。在操作方法中針對(duì)資源的操作類型與HTTP方法之間的匹配是通過應(yīng)用在它們上面的WebGetAttribute和WebInvokeAttribute特性來體現(xiàn)。
WebGetAttribute針對(duì)GET方法,而其他的HTTP方法則通過WebInvokeAttribute的Method屬性來體現(xiàn)。在IEmployeesService中,兩個(gè)用于獲取員工信息GetAll和Get方法均應(yīng)用了WebGetAttribute特性,而其他的Create、Update和Delete方法在應(yīng)用了WebInvokeAttribute特性,并且其Method屬性被分別設(shè)置為PUT、POST和DELETE。
WebGetAttribute和WebInvokeAttribute和均具有相同的屬性UriTemplate,該屬性用于定義作為最終操作URI的模板。我們不僅可以通過UriTemplate屬性為操作指定一個(gè)相對(duì)于終結(jié)點(diǎn)地址的靜態(tài)路徑,還可以通過占位符實(shí)現(xiàn)路徑中的動(dòng)態(tài)部分與參數(shù)之間的映射。
同樣以定義在契約接口IEmployeesService中的5個(gè)操作方法為例,如果終結(jié)點(diǎn)地址為http://127.0.0.1:3721/employees,由于用于返回所有員工列表的GetAll操作的UriTemplate被設(shè)置“All”,所以其地址為http://127.0.0.1:3721/employees。用于返回指定員工ID的Get操作的UriTemplate被設(shè)置成“{id}”,意味著我們直接在表示請(qǐng)求地址的URI中指定員工的ID,而它會(huì)自動(dòng)映射為該操作方法的參數(shù)id。用于刪除某個(gè)指定員工的Delete操作具有相同的UriTemplate設(shè)置,而用于創(chuàng)建添加新員工和修改現(xiàn)有員工信息的Create和Update操作,由于作為參數(shù)的Employee對(duì)象具有ID屬性,所以直接采用終結(jié)點(diǎn)地址。
二、創(chuàng)建/寄宿服務(wù)
在控制臺(tái)程序Service中我們定義了如下一個(gè)實(shí)現(xiàn)了契約接口IEmployeesService的服務(wù)類型EmployeesService。簡單 起見,我們直接通過一個(gè)靜態(tài)字段employees表示存儲(chǔ)的員工列表,該靜態(tài)字段在初始化的工作中被添加了兩個(gè)ID分別為001和002的Employee對(duì)象。針對(duì)員工信息的獲取、添加、修改和刪除的操作均在此列表中進(jìn)行。
1: public class EmployeesService : IEmployees 2: { 3: private static IList<Employee> employees = new List<Employee> 4: { 5: new Employee{ Id = "001", Name="張三", Department="開發(fā)部", 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: }值得一提的是,不論是用于獲取某個(gè)指定ID的員工信息的Get方法,還是用于修改和刪除員工記錄的Update和Delete方法,當(dāng)指定ID的員工不存在時(shí)都通過WebOperationContext表示當(dāng)前Web操作上下文的對(duì)象將回復(fù)狀態(tài)設(shè)置為NotFound(即404 Not Found),這體現(xiàn)了我們的服務(wù)是基于Web的。
接下來我們通過自我寄宿的方式對(duì)上面定義的EmployeesService服務(wù)進(jìn)行寄宿,下面是相應(yīng)的配置。我們?yōu)榧乃薜姆?wù)添加了唯一一個(gè)終結(jié)點(diǎn),并簡單地指定了其ABC三要素。和我們之前配置的終結(jié)點(diǎn)不同的是,在這里我們采用的綁定類型為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>最終我們通過如下的程序進(jìn)行服務(wù)的寄宿。之前我們總是使用基于服務(wù)類型創(chuàng)建的ServiceHost進(jìn)行服務(wù)寄宿,在這里我們使用的是ServiceHost它的子類WebServiceHost。
1: using (WebServiceHost host = new WebServiceHost(typeof(EmployeesService))) 2: { 3: host.Open(); 4: Console.Read(); 5: }三、進(jìn)行服務(wù)調(diào)用
由于我們寄宿的服務(wù)完全是基于Web的,所以和普通的Web站點(diǎn)沒有本質(zhì)的區(qū)別。由于EmployeesService服務(wù)的GetAll和Get操作支持HTTP-GET請(qǐng)求,所以我們完全可以在瀏覽器中針對(duì)操作的地址發(fā)起請(qǐng)求,而返回的數(shù)據(jù)可以直接顯示在瀏覽器上。下圖所示的是通過瀏覽器調(diào)用GetAll操作(http://127.0.0.1:3721/employees/all)得到的結(jié)果,我們可以看到所有員工的列表以XML的形式返回。
我們也可以通過瀏覽器調(diào)用Get操作并直接通過在地址中指定員工的ID(http://127.0.0.1:3721/employees/001)并得到以XML表示的基于相應(yīng)員工的信息。下圖所示XML正式ID為001的Employee對(duì)象序列化后的結(jié)果。如果在請(qǐng)求地址中指定一個(gè)不存在的ID(比如http://127.0.0.1:3721/employees/003),由于Get方法中指定了回復(fù)狀態(tài)為NotFound,我們會(huì)得到類似于訪問資源不存在的錯(cuò)誤信息,就像訪問一個(gè)不存在的Web頁面一樣。
上面我們演示了通過瀏覽器以HTTP-GET方式請(qǐng)求操作地址的方式從而直接將返回結(jié)果呈現(xiàn)出來,現(xiàn)在我們來演示如何使用通過ChannelFactory<TChannel>創(chuàng)建的服務(wù)代理進(jìn)行服務(wù)調(diào)用。我們首先在作為客戶端應(yīng)用程序的Client項(xiàng)目中創(chuàng)建一個(gè)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>如上面的配置片斷所示,我們定義了一個(gè)與服務(wù)端相匹配的客戶端終結(jié)點(diǎn),該終結(jié)點(diǎn)上應(yīng)用了一個(gè)WebHttpBehavior終結(jié)點(diǎn)行為。WebHttpBehavior可以說是整個(gè)Web HTTP編程模型的核心,絕大部分針對(duì)Web的支持都是通過該行為實(shí)現(xiàn)的。實(shí)際上服務(wù)端終結(jié)點(diǎn)通過WebServiceHost應(yīng)用了這個(gè)終結(jié)點(diǎn)行為。
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添加一個(gè)新員工(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: }服務(wù)調(diào)用程序如上所示,我們模擬了員工的添加、修改和刪除。程序之后會(huì)在客戶端控制臺(tái)產(chǎn)生如下的輸出。
所有員工列表:
1: 所有員工列表: 2: ID: 001 姓名: 張三 級(jí)別: G7 部門: 開發(fā)部 3: ID: 002 姓名: 李四 級(jí)別: G6 部門: 人事部 4:? 5: 添加一個(gè)新員工(003): 6: ID: 001 姓名: 張三 級(jí)別: G7 部門: 開發(fā)部 7: ID: 002 姓名: 李四 級(jí)別: G6 部門: 人事部 8: ID: 003 姓名: 王五 級(jí)別: G9 部門: 行政部 9:? 10: 修改員工(003)信息: 11: ID: 001 姓名: 張三 級(jí)別: G7 部門: 開發(fā)部 12: ID: 002 姓名: 李四 級(jí)別: G6 部門: 人事部 13: ID: 003 姓名: 王五 級(jí)別: G11 部門: 銷售部 14:? 15: 刪除員工(003)信息: 16: ID: 001 姓名: 張三 級(jí)別: G7 部門: 開發(fā)部 17: ID: 002 姓名: 李四 級(jí)別: G6 部門: 人事部從編程角度來看,我們采用與SOAP服務(wù)完全一樣的服務(wù)調(diào)用方式,那么如何反映出服務(wù)調(diào)用基于Web的本質(zhì)呢?首先,之前我們能夠通過瀏覽器訪問GetAll和Get兩個(gè)操作可以證明這兩個(gè)服務(wù)操作是基于HTTP-GET的,返回的數(shù)據(jù)直接以單純的XML返回,并沒有封裝成SOAP。為了證明Create、Update和Delete也是完全基于Web的,我們可以通過Fiddler來分析HTTP請(qǐng)求的內(nèi)容。
如下所示的三段XML片斷分別對(duì)應(yīng)著針對(duì)上述三個(gè)服務(wù)操作調(diào)用的HTTP請(qǐng)求消息,從這我們可以看出它們就是單純的針對(duì)PUT、POST和DELETE方法的HTTP請(qǐng)求,而傳輸給服務(wù)端的數(shù)據(jù)直接作為消息的主體,并沒有封裝成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)
轉(zhuǎn)載于:https://www.cnblogs.com/aweifly/p/3459377.html
總結(jié)
- 上一篇: js中文正则
- 下一篇: Objective-C策略模式(Stra