在[WS標准篇]中我花了很大的篇幅介紹了WS-MEX以及與它相關的WS規范:WS-Policy、WS-Transfer和WSDL,因為WCF元數據結構體系完全是基於WS-MEX等相關的規范之上。熟悉這些基本的WS規范,對於我們全面、深刻的理解WCF整個元數據架構體系具有十分重要的意義。不僅僅是針對元數據,對於後續章節陸續要介紹的內容,比如事務、可靠會話、安全等,我強烈建議讀者在正式進行相關部分的學習之前,先對相關的WS規范作一個大致的了解。
通過對WS-MEX的介紹,我們知道:不論是采用WS-Transfer Get操作還是Get Metadata操作,獲取到的元數據被封裝到回復消息主體部分的<Metadata>結點中,而<Metadata>是一組<MetadataSection>元素的集合。在托管的世界裡,<MetadataSection>元素和<MetadataSection>元素集合有相應的類型來表示,那就是我們接下來要著重介紹的MetadataSection和MetadataSet。
一、MetadataSection
MetadataSection定義在System.ServiceModel.Description命名空間下,用於用於定義基於某種方言(Dialect)的元數據,該類型和WS-MEX中包含元數據SOAP消息主體的<MetadataSection>結點相匹配。我們不妨現在看看MetadataSection的定義:
1: [XmlRoot(ElementName="MetadataSection", Namespace="http://schemas.xmlsoap.org/ws/2004/09/mex")]
2: public class MetadataSection
3: {
4: //其他成員
5: public MetadataSection();
6: public MetadataSection(string dialect, string identifier, object metadata);
7:
8: [XmlAnyAttribute]
9: public Collection<XmlAttribute> Attributes { get; }
10: [XmlAttribute]
11: public string Dialect { get; set; }
12: [XmlAttribute]
13: public string Identifier { get; set; }
14: [XmlElement("Location", typeof(MetadataLocation), Namespace="http://schemas.xmlsoap.org/ws/2004/09/mex")]
15: [XmlElement("MetadataReference", typeof(MetadataReference), Namespace="http://schemas.xmlsoap.org/ws/2004/09/mex")]
16: [XmlElement("Metadata", typeof(MetadataSet), Namespace="http://schemas.xmlsoap.org/ws/2004/09/mex")]
17: [XmlElement("schema", typeof(XmlSchema), Namespace = "http://www.w3.org/2001/XMLSchema")]
18: [XmlElement("definitions", typeof(ServiceDescription), Namespace = "http://schemas.xmlsoap.org/wsdl/")]
19: [XmlAnyElement]
20: public object Metadata { get; set; }
21:
22: //四種預定義元數據方言(Dialect)
23: //MEX:http://schemas.xmlsoap.org/ws/2004/09/mex
24: public static string MetadataExchangeDialect { get; }
25: //WS-Policy:http://schemas.xmlsoap.org/ws/2004/09/policy
26: public static string PolicyDialect { get; }
27: //WSDL:http://schemas.xmlsoap.org/wsdl/
28: public static string ServiceDescriptionDialect { get; }
29: //XML Schema:http://www.w3.org/2001/XMLSchema
30: public static string XmlSchemaDialect { get; }
31: }
但看MetadataSection的定義,你可能覺得沒有太多值得關注的地方,如果結合WS-MEX規范,既有很多值得玩味的地方了:
首先,在類型上應用了一個XmlRootAttribute特性,並定義的名稱和命名空間分別為:MetadataSection和http://schemas.xmlsoap.org/ws/2004/09/mex。這和WS-MEX 1.1完全吻合。
其次,屬性Dialect表述元數據方言,你可以定義任意字符串作為其屬性值。在WS-MEX定義了五種預定義元數據方言:MEX、XML Schema、WSDL、WS-Policy和WS-Policy Attachment。除了WS-Policy Attachement,MetadataSection為前面四種定義了靜態只讀屬性,以便方面編程使用。
然後,屬性Identifier表示元數據的標識符,這是一個以URI形式表示的字符串,由於受篇幅所限,在上面對WS-MEX的介紹中並沒有提及,有興趣的讀者可以參考WS-MEX官方文檔的第4部分。Identifier和Dialect最終被序列化後生成<MetadataSection>元素相應的屬性(Attribute)。此外,MetadataSection還定義了類型為Collection<XmlAttribute>的Attributes屬性,你可以自定義任意的XML屬性,最終將會作為<MetadataSection>元素的屬性。
而元數據的內容通過包含在屬性Metadata中,當整個MetadataSection被序列化後,該屬性的值將會被序列化成一個XML元素,其元素的名稱和命名空間根據具體的類型決定。從應用在該屬性上的一系列XmlElementAttribute特性我們可以看出:MetadataSection為以下幾種特殊的類型定義了相應的名稱和命名空間:
MetadataLocation
MetadataLocation表示以RUI形式表示的元數據文檔的地址,WS-MEX 1.1規定了可以采用元數據文檔地址的URI來替代相應元數據的內容。MetadataLocation定義在System.ServiceModel.Description命名空間下,定義如下:
1: [XmlRoot(ElementName="Location", Namespace="http://schemas.xmlsoap.org/ws/2004/09/mex")]
2: public class MetadataLocation
3: {
4: public MetadataLocation();
5: public MetadataLocation(string location);
6:
7: [XmlText]
8: public string Location { get; set; }
9: }
MetadataReference
按照WS-Addressing 2004或者WS-Addressing 1.0規范,如果元數據成為一種可被尋址的資源(Addressable Resource),那麼可以通過終結點引用(Endpoint Reference)的方式來定位該資源。WS-MEX 1.1規定了可以采用元數據終結點引用來替代相應元數據的內容。元數據終結點引用可以通過MetadataReference來表示,MetadataReference定義於System.ServiceModel.Description命名空間下,定義如下:
1: [XmlRoot(ElementName = "MetadataReference", Namespace = "http://schemas.xmlsoap.org/ws/2004/09/mex")]
2: public class MetadataReference : IXmlSerializable
3: {
4:
5: public MetadataReference();
6: public MetadataReference(EndpointAddress address, AddressingVersion addressVersion);
7: public EndpointAddress Address { get; set; }
8: public AddressingVersion AddressVersion { get; set; }
9: }
MetadataSet
MetadataSet就是我們即將要介紹的用於表示MetadataSection集合,將MetadataSet作為MetadataSection的元數據,意味元數據可以以一種嵌套的形式來表示。
XmlSchema
如果元數據的類型為XmlSchema,即表示以XML Schema方言(Dialect)表示的元數據。
ServiceDescription
關於這裡的ServiceDescription,讀者千萬要注意:這裡指的是System.Web.Services.Description.ServiceDescription,而不是System.ServiceModel.Description.ServiceDescription。後者是我們熟悉的對WCF服務的描述(對此不熟悉的讀者,可以參考《WCF技術剖析(卷1)》的第7章),前者實際上是對一個WSDL文檔的描述。由於WSDL的結構相對復雜,ServiceDescription的定義也不太簡單,篇幅所限,本書不會對此作詳細的介紹,有興趣的讀者可以參考MSDN類庫。如果元數據的類型為ServiceDescription,即表示以WSDL方言(Dialect)表示的元數據。
最後,MetadataSection還定義了如下三個靜態方法幫助你快速創建基於WS-Policy策略、XML Schema和WSDL元數據方言的MetadataSection對象:
1: [XmlRoot(ElementName="MetadataSection", Namespace="http://schemas.xmlsoap.org/ws/2004/09/mex")]
2: public class MetadataSection
3: {
4: //其他成員
5: public static MetadataSection CreateFromPolicy(XmlElement policy, string identifier);
6: public static MetadataSection CreateFromSchema(XmlSchema schema);
7: public static MetadataSection CreateFromServiceDescription(ServiceDescription serviceDescription);
8: }
二、 MetdataSet
MetadataSet是WS-MEX 1.1中置於SOAP消息主體部分整個元數據的描述,即對置於SOAP主體部分的<Metadata>所有內容的體現。既然<Metadata>結點是一組<MetadataSection>元素的集合,MetadataSet相應地也就是一組MetadataSection對象的集合,這可以從MetadataSet的定義看出來:
1: [XmlRoot("Metadata", Namespace="http://schemas.xmlsoap.org/ws/2004/09/mex")]
2: public class MetadataSet : IXmlSerializable
3: {
4: //其他成員
5: public MetadataSet();
6: public MetadataSet(IEnumerable<MetadataSection> sections);
7:
8: [XmlAnyAttribute]
9: public Collection<XmlAttribute> Attributes { get; }
10: [XmlElement("MetadataSection", Namespace="http://schemas.xmlsoap.org/ws/2004/09/mex")]
11: public Collection<MetadataSection> MetadataSections { get; }
12:
13: XmlSchema IXmlSerializable.GetSchema();
14: void IXmlSerializable.ReadXml(XmlReader reader);
15: void IXmlSerializable.WriteXml(XmlWriter writer);
16: }
三、WCF元數據架構模型
WCF通過終結點的形式將某個服務暴露出來,而元數據的目的在於幫助服務的消費者如何有效地與該終結點進行交互,以實現對該服務的正常調用。元數據幫助像SvcUtil.exe這樣的代碼生成工具能夠有效地生成客戶端代碼和配置。WCF在內部構建了一個完善的元數據架構體系,很好地實現了元數據的導出、發布、獲取和導入,這個框架體系對元數據的處理大體如圖1所示。
圖1 WCF元數據架構體系
從圖1可以看出,整個元數據框架體系大體分成服務端體系和客戶端體系,服務端復雜元數據的導出和發布,客戶端實現元數據的獲取與導入。元數據的導出、發布、獲取和導入這4個基本操作在整個框架體系中的分別實現以下的功能:
元數據導出(Exporting):將WCF服務相關的終結點列表轉換成MetadataSet對象,元數據的導出通過System.ServiceModel.Description.MetadataExporter實現;
元數據發布(Publishing):將導出的MetadataSet對象轉換成可被尋址的元數據資源通過相關的協議發布出來,WS-MEX和HTTP-GET是兩種常見的協議。元數據的發布通過System.ServiceModel.Description.ServiceMetadataBehavior服務行為實現;
元數據獲取(Retrieving):通過相應的協議(WS-MEX或者HTTP-GET)獲取發布出來的元數據資源,並轉換成MetadataSet對象。元數據的獲取通過System.ServiceModel.Description.MetadataExchangeClient實現;
元數據導入(Importing):將獲取元數據資源生成的MetadataSet對象最終轉換終結點對象,服務的消費者借助生成的終結點與服務端的終結點進行正常的交互。元數據導入通過System.ServiceModel.Description.MetadataImporter實現。
在後續的文章中,的我們將針對上述的四個元數據基本操作,對WCF的元數據框架的實現原理進行深入地剖析。