zoukankan      html  css  js  c++  java
  • WCF技术剖析之二十八:自己动手获取元数据[附源代码下载]

    元数据的发布方式决定了元数据的获取行为,WCF服务元数据架构体系通过ServiceMetadataBehavior实现了基于WS-MEXHTTP-GET的元数据发布,针对这两种不同的协议,元数据获取的实现方式也是不同的。我们首先来实现基于WS-MEX的元数据获取方式。 [Source Code从这里下载]

    一、 基于WS-MEX的元数据获取

    ServiceMetadataBehavior通过创建MEX终结点实现了基于WS-MEX的元数据的发布,从《如何将一个服务发布成WSDL》系列文章的介绍我们知道:元数据的发布实际上可以看成是在服务端寄宿一个元数据提供服务,我们通过服务调用的形式获取元数据。

    由于MEX终结点与一般意义上的终结点并没有本质的不同,我们只需要创建服务元数据发布方相匹配的终结点,相目标地址发送期望的请求消息,即可通过回复消息的形式获取元数据信息。现在以我们熟悉的计算服务为例,在服务寄宿的时候通过以下的配置为该服务添加一个MEX终结点,采用的MEX绑定和地址分别问:mexHttpBinding和http://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=" http://127.0.0.1:9999/calculatorservice" binding="ws2007HttpBinding" contract="Artech.MetataRetrieval.Services.ICalculator"/>
       7:         <endpoint address="http://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="http://127.0.0.1:3721/calculatorservice/metadata"/>
      14:         </behavior>
      15:       </serviceBehaviors>
      16:     </behaviors>
      17:   </system.serviceModel>
      18: </configuration>

    下面的代码展现了客户端获取元数据的程序,这和一般的服务调用并无二致。首先通过指定相应的绑定(MetadataExchangeBindings.CreateMexHttpBinding())和地址(元数据的目标地址:http://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("http://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, "http://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为运行后的截图。

    image 1 通过IE显示获取的元数据(以WS-MEX方式发布)

    二、 基于HTTP-GET的元数据获取

    上面我们通过自定的方式成功获取了服务端以WS-MEX方式发布的元数据,现在我们来是实现基于HTTP-GET的元数据获取方式。既然服务端采用了基于HTTP-GET的元数据发布方式,那么就意味着我们可以通过简单的HTTP请求的方式获取相应的元数据资源。

    同样是基于上面的例子,仔细的读者相信已经看到了,在计算服务的配置文件中,除了为服务添加MEX终结点之外,还通过ServiceMetadataBehavior开启了基于HTTP-GET的元数据发布方式,并将元数据发布地址指定为:http://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("http://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,在这里由于篇幅所限,并没有做这些工作。

    image 2 通过IE显示获取的元数据(以HTTP-GET方式发布)

    作者:Artech
    出处:http://artech.cnblogs.com
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    C语言中const关键字的用法
    LDO和DC-DC的概念,区别及优缺点
    Ubuntu下几个命令行方式使用的图片浏览工具
    I2C和I2S的区别和使用方法
    scikit-image 图像处理库介绍
    USB协议介绍
    Ubuntu 16.04 python和OpenCV安装
    一种基于python的人脸识别开源系统
    numpy 介绍
    python enumerate用法总结
  • 原文地址:https://www.cnblogs.com/artech/p/1634357.html
Copyright © 2011-2022 走看看