933
技術社區[雲棲]
WCF技術剖析之二十八:自己動手獲取元數據[附源代碼下載]
元數據的發布方式決定了元數據的獲取行為,WCF服務元數據架構體係通過ServiceMetadataBehavior實現了基於WS-MEX和HTTP-GET的元數據發布,針對這兩種不同的協議,元數據獲取的實現方式也是不同的。我們首先來實現基於WS-MEX的元數據獲取方式。 [Source Code從這裏下載]
一、 基於WS-MEX的元數據獲取
ServiceMetadataBehavior通過創建MEX終結點實現了基於WS-MEX的元數據的發布,從《如何將一個服務發布成WSDL》係列文章的介紹我們知道:元數據的發布實際上可以看成是在服務端寄宿一個元數據提供服務,我們通過服務調用的形式獲取元數據。
由於MEX終結點與一般意義上的終結點並沒有本質的不同,我們隻需要創建服務元數據發布方相匹配的終結點,相目標地址發送期望的請求消息,即可通過回複消息的形式獲取元數據信息。現在以我們熟悉的計算服務為例,在服務寄宿的時候通過以下的配置為該服務添加一個MEX終結點,采用的MEX綁定和地址分別問:mexHttpBinding和https://127.0.0.1:9999/calculatorservice/mex。
1: <?xml version="1.0" encoding="utf-8" ?>
2: <configuration>
3: <system.serviceModel>
4: <services>
5: <service name="Artech.MetataRetrieval.Services.CalculatorService" behaviorConfiguration="mexBehavior">
6: <endpoint address=" https://127.0.0.1:9999/calculatorservice" binding="ws2007HttpBinding" contract="Artech.MetataRetrieval.Services.ICalculator"/>
7: <endpoint address="https://127.0.0.1:9999/calculatorservice/mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
8: </service>
9: </services>
10: <behaviors>
11: <serviceBehaviors>
12: <behavior name="mexBehavior">
13: <serviceMetadata httpGetEnabled="true" httpGetUrl="https://127.0.0.1:3721/calculatorservice/metadata"/>
14: </behavior>
15: </serviceBehaviors>
16: </behaviors>
17: </system.serviceModel>
18: </configuration>
下麵的代碼展現了客戶端獲取元數據的程序,這和一般的服務調用並無二致。首先通過指定相應的綁定(MetadataExchangeBindings.CreateMexHttpBinding())和地址(元數據的目標地址:https://127.0.0.1:9999/calculatorservice/mex)創建ChannelFactory<TChannel>對象(由於MEX終結點契約類型為IMetadataExchange,這裏的TChannel類型為IMetadataExchange)。由於MEX終結點契約IMetadataExchange的Get方法的輸入參數和輸出參數均為Message對象,而是我們創建Message對象,並指定與WS-MEX匹配的Action。然後傳入通過ChannelFactory<TChannel>創建的服務代理中進行服務調用。最後從回複消息中提取出包含元數據的MetadataSet對象,並將其寫入一個XML文件中。
1: using System;
2: using System.Diagnostics;
3: using System.ServiceModel;
4: using System.ServiceModel.Channels;
5: using System.ServiceModel.Description;
6: using System.Text;
7: using System.Xml;
8: namespace Artech.MetataRetrieval
9: {
10: class Program
11: {
12: static void Main(string[] args)
13: {
14: MetadataSet metadata = null;
15: using (ChannelFactory<IMetadataExchange> channelFactory = new ChannelFactory<IMetadataExchange>(MetadataExchangeBindings.CreateMexHttpBinding(), new EndpointAddress("https://127.0.0.1:9999/calculatorservice/mex")))
16: {
17: IMetadataExchange proxy = channelFactory.CreateChannel();
18: using (proxy as IDisposable)
19: {
20: Message request = Message.CreateMessage(MessageVersion.Default, "https://schemas.xmlsoap.org/ws/2004/09/transfer/Get");
21: metadata = proxy.Get(request).GetBody<MetadataSet>();
22: }
23: }
24: using (XmlWriter writer = new XmlTextWriter("metadata.xml", Encoding.UTF8))
25: {
26: metadata.WriteTo(writer);
27: }
28: Process.Start("metadata.xml");
29: }
30: }
31: }
當程序成功執行,包含元數據的XML文件將會通過IE輸出(假設將IE作為默認的XML啟動程序),圖1為運行後的截圖。
二、 基於HTTP-GET的元數據獲取
上麵我們通過自定的方式成功獲取了服務端以WS-MEX方式發布的元數據,現在我們來是實現基於HTTP-GET的元數據獲取方式。既然服務端采用了基於HTTP-GET的元數據發布方式,那麼就意味著我們可以通過簡單的HTTP請求的方式獲取相應的元數據資源。
同樣是基於上麵的例子,仔細的讀者相信已經看到了,在計算服務的配置文件中,除了為服務添加MEX終結點之外,還通過ServiceMetadataBehavior開啟了基於HTTP-GET的元數據發布方式,並將元數據發布地址指定為:https://127.0.0.1:3721/calculatorservice/metadata。
下麵的代碼實現了相應的元數據獲取,其中我通過指定目標地址創建了一個HttpWebRequest對象,並通過該對象向元數據的發布地址發送請求。獲取的元數據將以HttpWebResponse的形式返回,由於獲取的元數據實際上是一個WSDL文檔,所以我們可以通過ServiceDescription的Read方法直接讀取生成一個ServiceDescription對象,並最終通過MetadataSection的靜態方法CreateFromServiceDescription將其轉換成一個MetadataSection對象。該MetadataSection對象被最終添加到創建的MetadataSet中,並被寫入一個XML文件。
1: using System.Diagnostics;
2: using System.Net;
3: using System.ServiceModel.Description;
4: using System.Xml;
5: using System.Text;
6: namespace Artech.MetataRetrieval
7: {
8: class Program
9: {
10: static void Main(string[] args)
11: {
12: MetadataSet metadata = new MetadataSet();
13: HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://127.0.0.1:3721/calculatorservice/metadata");
14: request.Method = "Get";
15: HttpWebResponse response = (HttpWebResponse)request.GetResponse();
16: using (XmlReader reader = XmlDictionaryReader.CreateTextReader(response.GetResponseStream(), new XmlDictionaryReaderQuotas()))
17: {
18: System.Web.Services.Description.ServiceDescription serviceDesc = System.Web.Services.Description.ServiceDescription.Read(reader);
19: metadata.MetadataSections.Add(MetadataSection.CreateFromServiceDescription(serviceDesc));
20: }
21: using (XmlWriter writer = new XmlTextWriter("metadata.xml", Encoding.UTF8))
22: {
23: metadata.WriteTo(writer);
24: }
25: Process.Start("metadata.xml");
26: }
27: }
28: }
當上麵的應用程序成功執行,包含獲取的元數據的XML將會通過IE打開,圖2為運行後的截圖。通過兩種方式獲取的元數據本質上是相同的,不過可能細心的讀者已經發現了:與上麵的例子(WS-MEX)獲取的MetadataSet不同,通過HTTP-GET獲取的MetadataSet僅僅包含一個元數據方言(Dialect)為WSDL的MetadataSection。這是因為,前麵的例子實際上將WSDL中引用(通過終結點地址或者資源地址)的內容都生成了相應的MetadataSection,在這裏由於篇幅所限,並沒有做這些工作。
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
最後更新:2017-10-27 16:34:13