閱讀193 返回首頁    go 阿裏雲 go 技術社區[雲棲]


WCF技術剖析之二十七: 如何將一個服務發布成WSDL[編程篇]

對於WCF服務端元數據架構體係來說,通過MetadataExporter將服務的終結點導出成MetadataSet(參考《如何導出WCF服務的元數據》),僅僅是完成了一半的工作。被成功導出的以MetadataSet對象表示的元數據需要最終作為可被訪問的網絡資源發布出來,才能被服務消費者獲取,進而有效地幫助他們進行服務調用。元數據的發布最終是通過ServiceMetadataBehavior這樣一個服務行為實現的,我們先來認識一下ServiceMetadataBehavior

一、 元數據發布的實現者:ServiceMetadataBehavior

ServiceMetadataBehavior是一個實現了IServiceBehavior的服務行為,它實現了基於如下兩種協議的元數據發布模式:

  • HTTP-GET:采用HTTP協議的Get操作,向元數據目標地址發送HTTP請求,並以查詢字符串(QueryString)的形式表示相應的查詢參數。元數據最終以HTTP回複的形式返回;
  • WS-MEX:元數據提供者按照WS-MEX規範創建終結點發布元數據,元數據消費者創建同樣基於WS-MEX的終結點與之交互,並最終通過SOAP的形式獲取元數據。關於WS-MEX,可以參考我的文章《元數據(Metadata)架構體係全景展現[WS標準篇]

我們首先通過如下得代碼來看看ServiceMetadataBehavior的定義,ServiceMetadataBehavior實現IServiceBehavior接口,並將所有發布元數據的行為定義在ApplyDispatchBehavior方法中。

   1: public class ServiceMetadataBehavior : IServiceBehavior
   2: {
   3:    
   4:     //其他成員
   5:     void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters);
   6:     void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase);
   7:     void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase);
   8:  
   9:     public Uri ExternalMetadataLocation { get; set; }    
  10:  
  11:     //HTTP
  12:     public bool HttpGetEnabled { get; set; }
  13:     public Uri HttpGetUrl { get; set; }
  14:     public Binding HttpGetBinding { get; set; }
  15:  
  16:     //HTTPS
  17:     public bool HttpsGetEnabled { get; set; }
  18:     public Binding HttpsGetBinding { get; set; }
  19:     public Uri HttpsGetUrl { get; set; }
  20:  
  21:     public MetadataExporter MetadataExporter { get; set; }
  22: }

ServiceMetadataBehavior定義了一係列的屬性用於控製具體的元數據發布行為,其中絕大部分是基於HTTP-GET發布模式的。ExternalMetadataLocation表示返回給客戶端的一個外部元數據地址,可以是絕對地址,也可以是基於HttpGetUrl或者HttpsGetUrl表述的相對地址;基於HTTP-GET的元數據發布同時支持HTTP和HTTPS兩種形式,Http(s)GetEnabled是控製是否允許基於HTTP(s)進行元數據發布的開關,Http(s)GetUrl和Http(s)GetBinding這指定了采用的地址和綁定;MetadataExporter屬性表示的MetadataExporter對象用於進行元數據的導出,默認為WsdlExporter

你可以通過配置的方式來設置除MetadataExporter之外的所有ServiceMetadataBehavior的屬性,此外,WCF還提供給你一些額外的配型項供你更好地控製元數據的發布行為。對於WCF的開發者或者實施者來說,當你沒有一份完備的文檔指導你進行基於服務行為或者終結點行為的配置時,你可以查看該行為對應的BehaviorExtensionElement的定義獲取與該行為相關的所有配置信息。ServiceMetadataBehavior相關的配置項全部定義在ServiceMetadataPublishingElement中,下麵給出了ServiceMetadataPublishingElement的定義:

   1: public sealed class ServiceMetadataPublishingElement : BehaviorExtensionElement
   2: {
   3:     //其他成員
   4:     public override Type BehaviorType { get; }
   5:     [ConfigurationProperty("externalMetadataLocation")]
   6:     public Uri ExternalMetadataLocation { get; set; }
   7:  
   8:     //HTTP
   9:     [ConfigurationProperty("httpGetEnabled", DefaultValue = false)]
  10:     public bool HttpGetEnabled { get; set; }
  11:     [ConfigurationProperty("httpGetUrl")]
  12:     public Uri HttpGetUrl { get; set; }
  13:     [StringValidator(MinLength=0), ConfigurationProperty("httpGetBinding", DefaultValue="")]
  14:     public string HttpGetBinding { get; set; }
  15:     [ConfigurationProperty("httpGetBindingConfiguration", DefaultValue=""), StringValidator(MinLength=0)]
  16:     public string HttpGetBindingConfiguration { get; set; }
  17:  
  18:     //HTTPS
  19:     [ConfigurationProperty("httpsGetEnabled", DefaultValue = false)]
  20:     public bool HttpsGetEnabled { get; set; }
  21:     [ConfigurationProperty("httpsGetUrl")]
  22:     public Uri HttpsGetUrl { get; set; }
  23:     [StringValidator(MinLength=0), ConfigurationProperty("httpsGetBinding", DefaultValue="")]
  24:     public string HttpsGetBinding { get; set; }
  25:     [StringValidator(MinLength=0), ConfigurationProperty("httpsGetBindingConfiguration", DefaultValue="")]
  26:     public string HttpsGetBindingConfiguration { get; set; }
  27:  
  28:     [ConfigurationProperty("policyVersion", DefaultValue="Default"), TypeConverter(typeof(PolicyVersionConverter))]
  29:     public PolicyVersion PolicyVersion { get; set; }
  30: }

通過對ServiceMetadataPublishingElement的定義我們可以看出:我們可以通過除MetadataExporter之外的所有ServiceMetadataBehavior的屬性,還可以通過policyVersion配置向指定具體采用的WS-Policy的版本。下麵是一個ServiceMetadataBehavior配置的例子:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:     <system.serviceModel>
   4:         <services>
   5:             <service behaviorConfiguration="MetadataPublishBehavior" name=" Artech.Services.CalculatorService">
   6:                 <endpoint address="https://127.0.0.1:3721/calcuulatorservice"
   7:                     binding="basicHttpBinding" bindingConfiguration="" contract=" Artech.Contracts.ICalculator" />                
   8:             </service>
   9:         </services>
  10:  
  11:       <behaviors>
  12:         <serviceBehaviors>
  13:           <behavior name="MetadataPublishBehavior">
  14:             <serviceMetadata externalMetadataLocation="https://127.0.1/mex/calculatorservice"
  15:                 httpGetEnabled="true" httpGetUrl="https://127.0.0.1/calculatorservice/mex"
  16:                 httpsGetEnabled="true" httpsGetUrl="https://127.0.0.1/calculatorservice/mex"
  17:                 policyVersion="Policy15" />
  18:           </behavior>
  19:         </serviceBehaviors>
  20:       </behaviors>
  21: </system.serviceModel>
  22: </configuration>

如果你希望通過WS-MEX的方式進行元數據的發布,你需要為服務添加一個基於WS-MEX的終結點。基於WS-MEX的終結點和一般意義上的終結點一樣由地址、綁定和契約三部分組成。其中,地址表示發布元數據的目標地址,而綁定和契約因為需要按照WS-MEX規範進行消息的交換,所以對綁定和契約具有特殊的要求。在具體對MEX終結點展開介紹之前,我們不妨先來看看如何通過配置的方式為服務添加MEX終結點:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:     <system.serviceModel>
   4:         <services>
   5:             <service name="Artech.Services.CalculatorService">
   6:                 <endpoint address="https://127.0.0.1:3721/calcuulatorservice"
   7:                     binding="basicHttpBinding" bindingConfiguration="" contract="Artech.Contracts.ICalculator" />
   8:                 <endpoint address="https://127.0.0.1:3721/calcuulatorservice/mex"
   9:                     binding="mexHttpBinding" bindingConfiguration="" contract="IMetadataExchange" />               
  10:             </service>
  11:         </services> 
  12:     </system.serviceModel>
  13: </configuration>

二、MEX 終結點有何不同?

我們通過為服務添加基於WS-MEX的終結點(以下簡稱MEX終結點)實現支持WS-MEX的元數據發布方式。總的來說,MEX終結點和一般意思上的終結點並沒有本質的不同,也是由地址、綁定和契約三要素構成。但是,為了支持WS-MEX規定的消息交換模式和請求/回複消息的結構,對契約和綁定具有一些特殊的要求,先來看看MEX終結點的契約。

1、MEX終結點的契約:IMetadataExchange

從上麵給出的基於MEX終結點的配置中,我們可以看到該終結點的契約被配置成“IMetadataExchange”。實際上IMetadataExchange是WCF內部定義的一個特殊服務契約接口,定義在System.ServiceModel.Description命名空間下,下麵是IMetadataExchange的定義:

   1: [ServiceContract(ConfigurationName = "IMetadataExchange", Name = "IMetadataExchange", Namespace = "https://schemas.microsoft.com/2006/04/mex")]
   2: public interface IMetadataExchange
   3: {
   4:      [OperationContract(Action = "https://schemas.xmlsoap.org/ws/2004/09/transfer/Get", ReplyAction = "https://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse", AsyncPattern = true)]
   5:     IAsyncResult BeginGet(Message request, AsyncCallback callback, object state);
   6:     Message EndGet(IAsyncResult result);
   7:     [OperationContract(Action = "https://schemas.xmlsoap.org/ws/2004/09/transfer/Get", ReplyAction = "https://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse")]
   8:     Message Get(Message request);
   9: }

從定義可以看出,IMetadataExchange實際上僅僅包含一個Get服務操作,其中Get方法是正常的同步模式服務操作,而BeginGet/EndGet是按照標準的異步操作模式對Get服務操作的定義(關於異步服務操作模式,在《WCF技術剖析(卷1)》的第4章有詳細的介紹)。

進一步分析IMetadataExchange的定義,由於通過ServiceContractAttribute特性將ConfigurationName屬性設定成“IMetadataExchange”,這也是為何在進行MEX終結點的配置的時候,契約可以直接配置成“IMetadataExchange”,而不是“System.ServiceModel.Description. IMetadataExchange”。

再來看看Get操作,通過OperationContractAttribute特性將Action和ReplyAction設置成了https://schemas.xmlsoap.org/ws/2004/09/transfer/Gethttps://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse,如果讀者《元數據(Metadata)架構體係全景展現[WS標準篇]》WS-Transfer相關介紹還有印象的話,應該知道它們就是WS-Transfer Get請求和回複SOAP消息對應的Action的值。在介紹WS—MEX的時候,我們提到過WS-MEX支持兩種形式的元數據獲取方式:WS-Transfer Get操作請求和Get Metadata操作請求。從這裏可以看出,WCF采用的是基於WS-Transfer Get操作的元數據請求方式。

2、MEX終結點的綁定:MetadataExchangeBindings

WCF專門為MEX終結點定製了一係列的綁定,以實現對不同的網絡傳輸協議(HTTP、HTTPS、TCP或者Named Pipe)的支持。這些定製的MEX綁定定義在MetadataExchangeBindings靜態類中,你可以通過相應CreateMexXxxBinding方法創建基於某種傳輸協議的綁定。MetadataExchangeBindings的定義如下:

   1: public static class MetadataExchangeBindings
   2: {
   3:     //其他成員
   4:     public static Binding CreateMexHttpBinding();
   5:     public static Binding CreateMexHttpsBinding();
   6:     public static Binding CreateMexTcpBinding();   
   7:     public static Binding CreateMexNamedPipeBinding(); 
   8: }

如果你采用編程的方式為服務添加MEX終結點,那麼你可以直接借助MetadataExchangeBindings創建相應的MEX綁定。如果采用配置的方式,僅僅需要將終結點的binding配置成:mexHttpBinding、mexHttpsBinding、mexTcpBinding和mexNamedPipeBinding即可,具體配置可以參考下麵:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:     <system.serviceModel>
   4:         <services>
   5:             <service behaviorConfiguration="MetadataPublishBehavior" name=" Artech.Services.CalculatorService">
   6:                 <endpoint address="https://127.0.0.1:3721/calcuulatorservice"
   7:                     binding="basicHttpBinding" bindingConfiguration="" contract="Artech.Contracts.ICalculator" />                
   8:                 <endpoint address="https://127.0.0.1/calculatorservice/mex" binding="mexHttpBinding" contract="IMetadataExchange" />
   9:                 <endpoint address="https://127.0.0.1/calculatorservice/mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
  10:                 <endpoint address="net.tcp://127.0.0.1/calculatorservice/mex"                    binding="mexTcpBinding" contract="IMetadataExchange" />
  11:                 <endpoint address="net.pipe://127.0.0.1/calculatorservice/mex"                    binding="mexNamedPipeBinding" contract="IMetadataExchange" />
  12:             </service>
  13:         </services>
  14:     </system.serviceModel>
  15: </configuration>

下一篇中,我們將會討論ServiceMetadataBehavior在內部是如何實現基於HTTP-GET和WS-MEX兩種協議的元數據發布的。


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

最後更新:2017-10-30 10:34:15

  上一篇:go  WCF技術剖析之二十六:如何導出WCF服務的元數據(Metadata)[擴展篇]
  下一篇:go  【雲計算的1024種玩法】ECS和輕量應用服務器的遠程控製入門