Windows Communication Foundation入門(Part Two)三、WCF的技術(shù)要素
WCF Service由一個Endpoints集合組成,每個Endpoint就是用于通信的入口,客戶端和服務(wù)端通過Endpoint交換信息,如下圖所示: 從圖中我們可以看到一個Endpoint由三部分組成:Address,Binding,Contract。便于記憶,我們往往將這三部分稱為是Endpoint的ABCs。 Address是Endpoint的網(wǎng)絡(luò)地址,它標(biāo)記了消息發(fā)送的目的地。Binding描述的是如何發(fā)送消息,例如消息發(fā)送的傳輸協(xié)議(如TCP,HTTP),安全(如SSL,SOAP消息安全)。Contract則描述的是消息所包含的內(nèi)容,以及消息的組織和操作方式,例如是one-way,duplex和request/reply。所以Endpoint中的ABCs分別代表的含義就是:where,how,what。當(dāng)WCF發(fā)送消息時,通過address知道消息發(fā)送的地址,通過binding知道怎樣來發(fā)送它,通過contract則知道發(fā)送的消息是什么。 在WCF中,類ServiceEndpoint代表了一個Endpoint,在類中包含的EndpointAddress,Binding,ContractDescription類型分別對應(yīng)Endpoint的Address,Binding,Contract,如下圖: EndpointAddress類又包含URI,Identity和可選的headers集合組成,如下圖:
Binding類包含Name,Namespace和BindingElement集合,如下圖:
BindingElement的順序也非常重要。BindingElement集合通常會創(chuàng)建一個用于通信的堆棧,其順序與BindingElement集合中元素順序一致。集合中最后一個binding element對應(yīng)于通信堆棧的底部,而集合中的第一個binding element則對應(yīng)于堆棧的頂端。入消息流的方向是從底部經(jīng)過堆棧向上,而出消息流的方向則從頂端向下。因此,BindingElement集合中的binding element順序直接影響了通信堆棧處理消息的順序。幸運的是,WCF已經(jīng)提供了一系列預(yù)定義的Binding,能夠滿足大多數(shù)情況,而不需要我們自定義Binding,殫精竭慮地考慮binding element的順序。 Contract是一組操作(Operations)的集合,該操作定義了Endpoint通信的內(nèi)容,每個Operation都是一個簡單的消息交換(message exchange),例如one-way或者request/reply消息交換。 類ContractDescription用于描述WCF的Contracts以及它們的操作operations。在ContractDescription類中,每個Contract的operation都有相對應(yīng)的OperationDescription,用于描述operation的類型,例如是one-way,還是request/reply。在OperationDescription中還包含了MessageDecription集合用于描述message。 在WCF編程模型中,ContractDescription通常是在定義Contract的接口或類中創(chuàng)建。對于這個接口或類類型,標(biāo)記以ServiceContractAttribute,而其Operation方法則標(biāo)記以O(shè)perationContractAttribute。當(dāng)然我們也可以不利用CLR的attribute,而采用手工創(chuàng)建。 與Binding一樣,每個Contract也包含有Name和Namespace,用于在Service的元數(shù)據(jù)中作為唯一性識別。此外,Contract中還包含了ContractBehavior的集合,ContractBehavior類型可以用于修改或擴展contract的行為。類ContractDescription的組成如下圖所示: 正如在ContractDescription中包含的IContractBehavior一樣,WCF專門提供了行為Behavior,它可以對客戶端和服務(wù)端的一些功能進行修改或者擴展。例如ServiceMetadataBehavior用于控制Service是否發(fā)布元數(shù)據(jù)。相似的,security behavior用于控制安全與授權(quán),transaction behavior則控制事務(wù)。 除了前面提到的ContractBehavior,還包括ServiceBehavior和ChannelBehaivor。ServiceBehavior實現(xiàn)了IServiceBehavior接口,ChannelBehaivor則實現(xiàn)了IChannleBehavior接口。 由于WCF需要管理的是服務(wù)端與客戶端的通信。對于服務(wù)端,WCF提供了類ServiceDescription用于描述一個WCF Service,;而針對客戶端,WCF管理的是發(fā)送消息時需要使用到的通道Channel,類ChannelDescription描述了這樣的客戶端通道。 ServiceDescription類的組成如下圖所示: 我們可以利用代碼的方式創(chuàng)建ServiceDescription對象,也可以利用WCF的Attribute,或者使用工具SvcUtil.exe。雖然可以顯式的創(chuàng)建它,但通常情況下,它會作為運行中的Service一部分而被隱藏于后(我在后面會提到)。 ChannelDescription類的組成與ServiceDescription大致相同,但它僅僅包含了一個ServiceEndpoint,用于表示客戶端通過通道通信的目標(biāo)Endpoint。當(dāng)然,施加到ChannelDescription的Behavior也相應(yīng)的為IChannelBehavior接口類型,如圖所示: 定義一個WCF Service非常簡單,以Hello World為例,定義的Service可能如下: System.ServiceModel是微軟為WCF提供的一個新的類庫,以用于面向服務(wù)的程序設(shè)計。在開發(fā)WCF應(yīng)用程序時,需要先添加對System.ServiceModel的引用。WCF中的大部分類和接口也都是在命名空間System.ServiceModel下。 我們?yōu)镠elloWorld類標(biāo)記了[ServiceContract],這就使得該類成為了一個WCF Service,而其中的方法Hello()則因為標(biāo)記了[OperationContract],而成為該Service的一個Operation。 不過WCF推薦的做法是將接口定義為一個Service,這使得WCF Service具有更好的靈活性,畢竟對于一個接口而言,可以在同時有多個類實現(xiàn)該接口,這也就意味著可以有多個Service Contract的實現(xiàn)。那么上面的例子就可以修改為: 而類HelloWorld則實現(xiàn)該IHello接口: 注意在實現(xiàn)了IHello接口的類HelloWorld中,不再需要在類和方法中標(biāo)注ServiceContractAttribute和OperationContractAttribute了。 前面我已經(jīng)提過,一個WCF Service必須有host作為它運行的環(huán)境。這個host可以是ASP.Net,可以是Windows Service,也可以是一個普通的應(yīng)用程序,例如控制臺程序。下面就是一個Host的實現(xiàn): 在這個HostApp中,我們?yōu)镠elloWorld創(chuàng)建了一個ServiceHost對象。通過它就可以創(chuàng)建WCF運行時(Runtime),WCF Runtime是一組負責(zé)接收和發(fā)送消息的對象。ServiceHost可以創(chuàng)建SerivceDescription對象,利用SerivceDescription,SercieHost為每一個ServiceEndpoint創(chuàng)建一個EndpointListener。ServiceHost的組成如下圖:
注意在創(chuàng)建ServiceHost時,傳遞的type類型參數(shù),不能是interface。因此,我在這里傳入的是typeof(HelloWorld)。ServiceHost類的AddServiceEndpoint()方法實現(xiàn)了為Host添加Endpoint的功能,其參數(shù)正好是Endpoint的三部分:Address,Bingding和Contract。(此時的IHello即為ServiceContract,其方法Hello為OperationContract)。 ServiceHost的Open()方法用于創(chuàng)建和打開Service運行時,而在程序結(jié)束后我又調(diào)用了Close()方法,來關(guān)閉這個運行時。實際上以本例而言,該方法可以不調(diào)用,因為在應(yīng)用程序結(jié)束后,系統(tǒng)會自動關(guān)閉該host。但作為一種良好的編程習(xí)慣,WCF仍然要求顯式調(diào)用Close()方法,因為Service運行時其本質(zhì)是利用Channel來完成消息的傳遞,當(dāng)打開一個Service運行時的時候,系統(tǒng)會占用一個Channel,調(diào)用完后,我們就需要釋放對該通道的占用。當(dāng)然我們也可以用using語句來管理ServiceHost資源的釋放。 定義好了一個WCF Service,并將其運行在Host上后,如何實現(xiàn)它與客戶端的通信呢?典型的情況下,服務(wù)端與客戶端均采用了Web Service Description Language(WSDL),客戶端可以通過工具SvcUtil.exe生成對應(yīng)于該WCF Service的Proxy代碼,以完成之間的消息傳遞,如圖所示: SvcUtil.exe是由WinFx Runtime Component SDK所提供的,如果安裝SDK正確,可以在其中找到該應(yīng)用工具。生成客戶端Proxy代碼的方法很簡單,首先需要運行服務(wù)端Service。然后再命令行模式下運行下面的命令: 這樣會在當(dāng)前目錄下產(chǎn)生兩個文件output.cs和output.config。前者最主要的就是包含了一個實現(xiàn)了IHello接口的Proxy對象,這個代理對象名為HelloProxy,代碼生成的結(jié)果如下: 至于后者,則是WCF Service的配置信息,主要包含的是Endpoint中Address,Binding以及Contract的配置(在后續(xù)文章我會詳細介紹)。 現(xiàn)在客戶端就可以直接使用HelloProxy對象,來完成與服務(wù)端的通信了: 除了可以使用SvcUtil工具產(chǎn)生客戶端代碼,同樣我們也可以利用代碼的方式來完成客戶端。客戶端在發(fā)送消息給服務(wù)端時,其通信的基礎(chǔ)是Service的Endpoint,WCF提供了System.ServiceModel.Description.ServiceEndpoint類,通過創(chuàng)建它來實現(xiàn)兩端的通信。在前面,我還提到“對于客戶端而言,WCF管理的是發(fā)送消息時需要使用到的通道Channel”,為此,WCF提供了ChannelFactory(其命名空間為System.ServiceModel.Channel),專門用于創(chuàng)建客戶端運行時(runtime)。ChannelFactory與ServiceHost相對應(yīng),它可以創(chuàng)建ChannelDescription對象。與服務(wù)端ServiceHost不同的是,客戶端并不需要偵聽器,因為客戶端往往是建立連接的“發(fā)起方”,并不需要偵聽進來的連接。因此客戶端的Channel Stack會由ChannelDescription創(chuàng)建。 ChannelFactory和ServiceHost都具有Channel Stack,而服務(wù)端與客戶端的通信又是通過channel來完成,這就意味著,利用ChannelFactory,客戶端可以發(fā)送消息到服務(wù)端。而客戶端本身并不存在Service對象,因此該Service的Proxy,是可以通過Channel來得到的。所以客戶端的代碼可以修改如下: public class ClientApp using (ChannelFactory<IHello> factory = new ChannelFactory<IHello>(httpEndPoint)) 對于上面的代碼,我們有兩點需要注意: 對于服務(wù)端而言,我們也可以直接在瀏覽器中打開該Service,在地址欄中輸入http://localhost:8080/HelloService,如下圖: 點擊鏈接:http://localhost:8080/HelloService?wsdl,我們可以直接看到HelloService的WSDL。注意到在這里我并沒有使用IIS,實際上WCF內(nèi)建了對httpsys的集成,允許任何應(yīng)用程序自動成為HTTP listener。 <未完待續(xù)> posted on 2006-04-10 08:37 張逸 閱讀(5251) 評論(4) 編輯 收藏 所屬分類: WCF & SOA |
|