閱讀387 返回首頁    go 汽車大全


WCF技術剖析之二十: 服務在WCF體係中是如何被描述的?

任何一個程序都需要運行於一個確定的進程中,進程是一個容器,其中包含程序實例運行所需的資源。同理,一個WCF服務的監聽與執行同樣需要通過一個進程來承載。我們將為WCF服務創建或指定一個進程的方式稱為服務寄宿(Service Hosting)。服務寄宿的本質通過某種方式,創建或者指定一個進程用以監聽服務的請求和執行服務操作,為服務提供一個運行環境。

服務寄宿的方式大體分兩種:一種是為一組WCF服務創建一個托管的應用程序,通過手工啟動程序的方式對服務進行寄宿,所有的托管的應用程序均可作為WCF服務的宿主,比如Console應用、Windows Forms應用和ASP.NET應用等,我們把這種方式的服務寄宿方式稱為自我寄宿(Self Hosting)。另一種則是通過操作係統現有的進程激活方式為WCF服務提過宿主,Windows下的進程激活手段包括IIS、Windows Service或者WAS(Windows Process Activation Service)等。

服務寄宿的手段是為一個WCF服務類型創建一個ServiceHost對象(或者任何繼承於ServiceHostBase的對象)。無論采用哪種寄宿方式,在為某個服務創建ServiceHost的過程中,WCF框架內部會執行一係列的操作,其中最重要的步驟就是為服務創建服務描述(Service Description)。在本篇文章中,我們將對服務描述進行全麵的介紹。

WCF服務描述通過類型System.ServiceModel.Description.ServiceDescription表示,ServiceDescription對象是WCF服務運行時的描述。除了包含WCF服務的一些基本信息,比如服務的名稱、命名空間和CLR類型等,ServiceDescription還包含服務所有終結點和服務行為的描述。

一、 ServiceDescription與ServiceBehavior

從下麵ServiceDescription的定義可以看出,ServiceDescription中定義了一係列屬性,它們的含義如下:

  • Behaviors服務行為(Service Behavior)的集合
  • ConfigurationName:服務的在配置文件中的名稱,默認為服務類型的全名(命名空間+類型名稱)
  • Name服務的名稱,默認為服務類型名稱(不包含命名空間)
  • Namespace服務的命名空間,默認為“https://tempuri.org/”
  • ServiceType服務的CLR類型
   1: public class ServiceDescription
   2: {
   3:     //其他成員
   4:     public KeyedByTypeCollection<IServiceBehavior> Behaviors { get; }
   5:     public string ConfigurationName { get; set; }
   6:     public ServiceEndpointCollection Endpoints { get; }
   7:     public string Name { get; set; }
   8:     public string Namespace { get; set; }
   9:     public Type ServiceType { get; set; }
  10: }

1、Name與Namespace

ServiceDescription的NameNamespace分別表示服務的名稱和命名空間,這兩個屬性同樣體現在服務發布的WSDL中。可以通過System.ServiceModel.ServiceBehaviorAttributeNameNamespace屬性進行設定。ServiceDescription的Name和Namespace的默認值分別為服務類型名稱和https://tempuri.org/,所以下麵兩種定義是等效的。

   1: [ServiceBehavior] 
   2: public class CalculatorService : ICalculator 
   3: { 
   4:     //省略成員 
   5: } 
   1: [ServiceBehavior(Name = "CalculatorService", Namespace = "https://tempuri.org/")]
   2: public class CalculatorService : ICalculator
   3: {
   4:     //省略成員
   5: }

而ServiceDescription的Namespace映射WSDL的目標命名空間(targetNamespace),Name則直接對應<wsdl:service>節點的Name屬性。在下麵的服務定義中,通過ServiceBehaviorAttribute將Name和Namespace設置為“CalcService”和“http://www.artech.com/”,後麵的XML體現了服務在WSDL表示。

   1: [ServiceBehavior(Name = "CalcService", Namespace = "https://www.artech.com/")]
   2: public class CalculatorService : ICalculator
   3: {
   4:     //省略成員
   5: }
   1: <?xml version="1.0" encoding="utf-8"?>
   2: <wsdl:definitions name="CalcService" targetNamespace= http://www.artech.com/ 
   3: ...>
   4:     ......
   5:     <wsdl:service name="CalcService">
   6:         ......
   7:     </wsdl:service>
   8: </wsdl:definitions>

2、ConfigurationName

ServiceDescription的ConfiguraitonName表示服務的配置名稱,可以同樣可以通過System.ServiceModel.ServiceBehaviorAttribute的同名屬性進行設定。在默認情況下,ConfiguraitonName的值為服務類型的全名(命名空間+類型名稱),下麵兩種服務的定義是等效的。

   1: namespace Artech.ServiceDescriptionDemos
   2: {    
   3:     [ServiceBehavior]
   4:     public class CalculatorService : ICalculator
   5:     {
   6:         //省略成員
   7:     }
   8: }
   1: namespace Artech.ServiceDescriptionDemos
   2: {    
   3:     [ServiceBehavior(ConfigurationName = "Artech.ServiceDescriptionDemos.CalculatorService")]
   4:     public class CalculatorService : ICalculator
   5:     {
   6:         //省略成員
   7:     }
   8: }

如果配置文件中<service>的Name屬性更改了,在服務定義中需要通過ServiceBehaviorAttribute對ConfigurationName進行相應的修正,如下麵的代碼所示。

   1: namespace Artech.ServiceDescriptionDemos
   2: {    
   3:     [ServiceBehavior(ConfigurationName = "CalculatorService")]
   4:     public class CalculatorService : ICalculator
   5:     {
   6:      //省略成員
   7:     }
   8: }
   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:     <system.serviceModel>        
   4:         <services>
   5:             <service name="CalculatorService">
   6:                 ......
   7:             </service>
   8:         </services>
   9:     </system.serviceModel>
  10: </configuration>

3、服務行為(Service Behavior)

如果說契約(Contract)是涉及雙邊的描述(契約是服務的提供者和服務消費者進行交互的依據),那麼行為(Behavior)就是基於單邊的描述。客戶端行為體現的是WCF如何進行服務調用的方式,而服務端行為則體現了WCF的請求分發方式。行為是對WCF進行擴展的最為重要的方式,按照行為作用域的不同,WCF的行為大體包含以下四種:

  • 服務行為(Service Behavior):基於服務本身的行為,實現了接口System.ServiceModel.Description.IServiceBehavior,可以通過Attribute或者配置的方式進行指定
  • 終結點行為(Endpoint Behavior):基於某個服務終結點(客戶端或者服務端)的行為,實現了接口System.ServiceModel.Description.IEndpointBehavior,可以通過配置的方式進行指定
  • 契約行為(Contract Behavior):基於某個服務契約的行為,作用於實現了該契約的所有服務(服務端行為)和基於該契約進行服務調用的服務代理(客戶端行為),實現了接口System.ServiceModel.Description.IContractBehavior,可以通過Attribute的方式進行指定
  • 操作行為(Operation Behavior):基於服務契約中的某個操作契約,作用於實現了該服務契約的服務對應的服務操作(DispatchOperation)和基於該操作契約進行服務調用的客戶操作(ClientOperation),實現了接口System.ServiceModel.Description.IOperationBehavior,可以通過Attribute進行指定

在ServiceDescription中,類型為KeyedByTypeCollection<IServiceBehavior>的Behaviors屬性表示服務所有的服務行為集合。所有的服務行為都實現了System.ServiceModel.Description.IServiceBehavior接口。IServiceBehavior定義如下,從中可以看出IServiceBehavior定義了如下三個方法。

注:KeyedByTypeCollection<T>可以看成是以T實例為Value,Value對象真實類型為Key的Dictionary,可以通過類型定位並獲取相應的成員對象

  • AddBindingParameters為某個自定義綁定元素(Custom Binding Element)添加綁定參數,以指導或者確保綁定元素的正常操作,比如通過設置的綁定參數創建相應的信道
  • ApplyDispatchBehavior通過改變WCF服務端分發係統的屬性,或者添加/替換分發係統中用以實現某種分發操作的可擴展對象,進而改變服務分發的行為
  • Validate:通過檢驗服務描述,用以保證後續工作的正常執行
   1: public interface IServiceBehavior
   2: {
   3:     void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters);
   4:     void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase);
   5: void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase);
   6: }

WCF為我們預定義了一係列的ServiceBehavior,其中ServiceBehaviorAttribute就是其中之一。ServiceBehaviorAttribute不僅僅是一個自定義特性(Custom Attribute),實際上它本身就是一個實現了IServiceBehavior的服務行為。

   1: [AttributeUsage(AttributeTargets.Class)]
   2: public sealed class ServiceBehaviorAttribute : Attribute, IServiceBehavior
   3: {
   4:     //省略成員
   5: }

對於其他一些預定義服務行為,比如用於實現與ASP.NET兼容的AspNetCompatibilityRequirementsAttribute;用於進行限流控製的ServiceThrottlingBehavior;用於進行服務授權的ServiceAuthorizationBehavior等,可以通過配置的方式應用於某個WCF服務。

對於ServiceDescription來說,最重要的要數System.ServiceModel.Description.ServiceEndpointCollection類型的Endpoints屬性。該屬性表示為服務添加的所有在終結點集合,集合的每個元素為System.ServiceModel.Description.ServiceEndpoint對象,接下來我們就來著重討論ServiceEndpoint。

二、 ServiceEndpoint與EndpointBehavior

ServiceEndpoint對象是對終結點的運行時描述,終結點的三要素(ABC:Address、Binding、Contract)分別由同名的屬性表示。ListenUri和ListenUriMode表示終結點真正的監聽地址和監聽模式,Address和ListenUri由被稱為邏輯地址和物理地址(關於邏輯地址和物理地址,可以參考[原創]WCF後續之旅(15): 邏輯地址和物理地址)。

   1: public class ServiceEndpoint
   2: {
   3:     //其他成員
   4:     public EndpointAddress Address { get; set; }
   5:     public KeyedByTypeCollection<IEndpointBehavior> Behaviors { get; }
   6:     public Binding Binding { get; set; }
   7:     public ContractDescription Contract { get; }
   8:     public Uri ListenUri { get; set; }
   9:     public ListenUriMode ListenUriMode { get; set; }
  10:     public string Name { get; set; }
  11: }

在ServiceEndpoint中,類型為KeyedByTypeCollection<IEndpointBehavior>的Behaviors屬性表示綁定到該終結點的終結點行為(Endpoint Behavior)集合。集合的成員為實現了IEndpointBehavior接口的終結點行為對象。IEndpointBehavior的定義如下,AddBindingParameters、ApplyDispatchBehavior和Validate與IServiceBehavior同名方法語義類似。不同的是,IEndpointBehavior的所有方法的作用域僅限於當前終結點,並且IEndpointBehavior既可以作用於服務端,也可以用於客戶端。為此,增加了一個新的方法:ApplyClientBehavior。ApplyClientBehavior方法與ApplyDispatchBehavior相對,通過修改客戶端運行時(Client Runtime)的屬性,或者添加/替換客戶端運行時某些可擴展對象,進而實現控製客戶端行為的目的。

   1: public interface IEndpointBehavior
   2: {
   3:     void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters);
   4:     void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime);
   5:     void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher);
   6: void Validate(ServiceEndpoint endpoint);
   7: }

終結點的契約通過ContractDescription對象表示,為了讓大家對服務描述有一個係統的認識,接下來我們繼續介紹ContractDescription。

三、ContractDescription和ContractBehavior

System.ServiceModel.Description.ContractDescription定義了以下一些屬性用於描述服務契約。由於服務契約通過System.ServiceModel.ServiceContractAttribute定義,所以大部分的屬性都和ServiceContractAttribute的屬性相匹配,在這裏就不再作重複的介紹了。

   1: public class ContractDescription
   2: {
   3:     //其他成員
   4:     public KeyedByTypeCollection<IContractBehavior> Behaviors { get; }
   5:     public OperationDescriptionCollection Operations { get; }
   6: }

在ContractDescription中,類型為KeyedByTypeCollection<IContractBehavior>的屬性Behaviors代表基於服務契約的契約行為(Contract Behavior)集合,集合成員為實現了接口IContractBehavior的契約行為對象。IContractBehavior具有與IEndpointBehavior一樣的方法成員,但是契約行為作用於實現了該服務契約的所有服務(服務端行為),基於使用該服務契約進行服務調用的服務代理(客戶端行為)。

   1: public interface IContractBehavior
   2: {
   3:     void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters);
   4:     void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime);
   5:     void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime);
   6: void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint);
   7: }

ContractDescription的Operations屬性表示服務契約的所有操作的描述,類型為OperationDescriptionCollection,表示一個OperationDescription對象的集合。接下來,我們來介紹OperationDescription。

四、 OperationDescription和OperationBehavior

System.ServiceModel.Description.OperationDescription定義了一係列的屬性用以描述定義在服務契約中操作契約。由於操作契約通過System.ServiceModel.OperationContractAttribute定義,所以OperationDescription的大部分屬性與OperationContractAttribute屬性一一匹配,在這裏就不再作重複的介紹了。

   1: public class OperationDescription
   2: {
   3:     //其他成員
   4:     public KeyedByTypeCollection<IOperationBehavior> Behaviors { get; }    
   5: }

上麵我不止一次地提出客戶端操作(Client Operation)和服務端操作(Dispatch Operation)的概念,這是由於在運行時,基於相同的OperationDescription創建操作對象在客戶端和服務端是不同的,服務端操作稱為分發操作(DispatchOperation),通過類型System.ServiceModel.Dispatcher.DispatchOperation 表示,客戶端操作通過類型System.ServiceModel.Dispatcher.ClientOperation 表示。

在OperationDescription中,類型為KeyedByTypeCollection<IOperationBehavior>的Behaviors屬性表示基於操作的所有操作行為(Operation Behavior)集合,集合成員為實現了IOperationBehavior接口的類型對象。IOperationBehavior具有與IEndpointBehavior、IContractBehavior一樣的方法成員。IOperationBehavior的作用域僅限於當前的操作(客戶端操作或者服務端操作)。

   1: public interface IOperationBehavior
   2: {
   3:     void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters);
   4:     void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation);
   5:     void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation);
   6: void Validate(OperationDescription operationDescription);
   7: }

作者:蔣金楠
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
原文鏈接

最後更新:2017-10-30 11:35:00

  上一篇:go  WCF技術剖析之十九:深度剖析消息編碼(Encoding)實現(下篇)
  下一篇:go  如何用數據驅動企業研發效率提升?雲效2.0新品度量實踐解讀