元数据的导出就是实现从ServiceEndpoint对象向MetadataSet对象转换的过程,在WCF元数据框架体系中,元数据的导出工作由MetadataExporter实现。MetadataExporter是一个抽象类型,定义了导出元数据的基本行为。WCF定义一个具体的MetadataExporter:WsdlExporter,将基于某个终结点的元数据导出生成基于WSDL的MetadataSet。我们先来认识MetadataExporter和MetadataSet。

一、MetadataExporter

MetadataExporter是一个定义在System.ServiceModel.Description命名空间下抽象类型,下面的代码片断给出了MetadataExporter的定义。MetadataExporter定义了3个与元数据导出相关的方法,其中ExportContract仅仅导出基于某个服务契约相关的元数据,ExportEndpoint则导出某个终结点相关的所有元数据。这两个方法并不直接返回用于承载元数据信息的MetadataSet对象,而是将导出的元数据暂存于元数据转换的上下文中,最终通过GetGeneratedMetadata方法从该元数据转换上下文中将导出的元数据提取出来。

   1: public abstract class MetadataExporter
   2: {    
   3:     public abstract void ExportContract(ContractDescription contract);
   4:     public abstract void ExportEndpoint(ServiceEndpoint endpoint);
   5:     public abstract MetadataSet GetGeneratedMetadata();
   6:  
   7:     public Collection<MetadataConversionError> Errors { get; }
   8:     public PolicyVersion PolicyVersion { get; set; }
   9:     public Dictionary<object, object> State { get; }   
  10: }

此外, MetadataExporter还定义了三个属性Errors、PolicyVersion和State。Errors是一个MetadataConversionError对象的集合,包含一些在进行元数据导出过程中出现的错误或者警告消息,我们可以利用它来进行一些相应的异常处理;字典类型的State可以作为一个容器盛放一些在进行元数据导出过程中动态使用到的对象;而PolicyVersion代表元数据基于的WS-Policy规范的版本。PolicyVersion的定义如下,由于定义的构造函数是私有的,所以不能直接利用new操作符创建该对象,只能通过定义在PolicyVersion中的两个静态只读属性Policy12和Policy15得到代表WS-Policy 1.2和WS-Policy 1.5的PolicyVersion对象。静态属性Default代表默认的WS-Policy版本,目前为WS-Policy 1.2。属性Namespace表示相应WS-Policy版本的命名空间。

   1: public sealed class PolicyVersion
   2: {
   3:     //其他成员
   4:     private PolicyVersion(string policyNamespace);
   5:     public static PolicyVersion Default { get; }
   6:     public string Namespace { get; }
   7:     public static PolicyVersion Policy12 { get; }
   8:     public static PolicyVersion Policy15 { get; }
   9: }

WCF定义了一个具体的MetadataExporter类型用于将终结点导出为基于WSDL的MetadataSet,即WsdlExporter。

二、WsdlExporter

通过《元数据(Metadata)架构体系全景展现[WS标准篇]》的介绍,我们知道了元数据具有3三种主要的表现形式:XML SchemaWS-Policy策略WSDL,而且WSDL可以直接采用XML Schema表示Web服务使用到的数据和消息类型,采用基于WS-Policy的策略断言定义其绑定行为,基本上一个WSDL文档可以用于表示Web服务的所有信息。

正是因为WSDL是目前描述Web服务做好的语言,建立WCF终结点与WSDL元素之间的匹配关系,以及基于该匹配关系的元数据导入和导出的实现,是WCF元数据框架体系的一个最为重要的目标。在第1节对WSDL的介绍中,我们已经谈过了WCF下终结点三要素(地址、绑定和契约)与组成一份完成WSDL文档(基于WSDL 1.1)的5个元素之间的匹配关系,现在我们进行一个简单的总结。组成WSDL的5个元素(Service、Binding、PortType、Message和Type)与终结点三要素之间的匹配关系大体上可以通过图1来体现,其中WSDL元素之间的箭头代表引用关系,WSDL和ServicePoint之间的箭头表示匹配关系。

图1 WSDL各元素和终结点三要素之间的匹配关系

图1我们不难看出:WSDL中Service元素的一个Port元素实际上就代表着整个ServiceEndpoint对象,Port下的Address元素即终结点的地址;WSDL中的Binding元素实际上和终结点的绑定表示相同的内容;而终结点的契约则和一个PortType元素相匹配。

既然WSDL和ServiceEndpoint之间存在着一个如此清晰的匹配关系,那么直接将一个ServiceEndpoint对象导出成一个基于WSDL的MetadataSet就不会是一件很难的事情,WsdlExporter就是为实现这样的目标而设计。

在具体对WsdlExporter进行介绍之前,我们不妨先来看看WsdlExporter的定义。从下面给出的代码片断中,我们可以看到WsdlExporter直接继承MetadataExporter。除了重写定义在MetadataExporter三个抽象方法之外,还定义了一个ExportEndpoints方法帮助我们将一个包含多个终结点的服务作为一个整体导出,因为一个WSDL本身就是对一个完整的Web服务的描述。

   1: public class WsdlExporter : MetadataExporter
   2: {
   3:     //其他成员    
   4:     public override void ExportContract(ContractDescription contract);
   5:     public override void ExportEndpoint(ServiceEndpoint endpoint);
   6:     public void ExportEndpoints(IEnumerable<ServiceEndpoint> endpoints, XmlQualifiedName wsdlServiceQName);
   7:     public override MetadataSet GetGeneratedMetadata();
   8:  
   9:     public ServiceDescriptionCollection GeneratedWsdlDocuments { get; }
  10:     public XmlSchemaSet GeneratedXmlSchemas { get; }
  11: }

此外,WsdlExporter还定义了两个只读属性,GeneratedWsdlDocuments属性以ServiceDescription集合的形式返回导出生成的WSDL文档;GeneratedXmlSchemas则返回导出生成作为描述数据和消息类型的XML Schema。

三、 实例演示:如何通过WsdlExporter导出元数据

为了让读者更见深刻地认识WsdlExporter,我们现在做一个简单的实例演示。我们通过一个简单的控制台(Console)应用作为演示程序。首先我们先演示如何利用WsdlExporter导出一个终结点,为此我们定义了一个处理订单的服务契约,契约接口和使用到的数据类型(数据契约)定义如下:

   1: using System;
   2: using System.ServiceModel;
   3: namespace Artech.MetadataExporting
   4: {
   5:     [ServiceContract(Namespace="http://www.artech.com/")]
   6:     public interface IOrderService
   7:     {
   8:         [OperationContract]
   9:         void ProcessOrder(Order order);
  10:     }   
  11: }

   1: using System.Collections.ObjectModel;
   2: using System.Runtime.Serialization;
   3: namespace Artech.MetadataExporting
   4: {
   5:     [DataContract(Namespace="http://www/artech.com/types/")]
   6:     public class Order
   7:     {
   8:         [DataMember]
   9:         public string OrderId { get; set; }
  10:         [DataMember]
  11:         public string CustomerId { get; set; }
  12:         [DataMember]
  13:         public Collection<OrderDetail> Details { get; set; }
  14:     }
  15:  
  16:     [DataContract(Namespace = "http://www/artech.com/types/")]
  17:     public class OrderDetail
  18:     {
  19:         [DataMember]
  20:         public string OrderId { get; set; }
  21:         [DataMember]
  22:         public string ProductId { get; set; }
  23:         [DataMember]
  24:         public int Quantity { get; set; }
  25:     }
  26: }

接下来,通过下面的代码创建两个ServiceEndpoint对象和一个表示服务有效名称(QName)的XmlQualifiedName对象,传入WsdlExporter的ExportEndpoints方法。通过调用GetGeneratedMetadata方法获取包含有所有导出元数据的MetadataSet对象,并将其写入到一个XML文件中。最终调用Process的静态Start方法打开该XML文件。

   1: using System.Diagnostics;
   2: using System.ServiceModel;
   3: using System.ServiceModel.Description;
   4: using System.Text;
   5: using System.Xml;
   6: namespace Artech.MetadataExporting
   7: {
   8:     class Program
   9:     {
  10:         static void Main(string[] args)
  11:         {
  12:             ContractDescription contract =  ContractDescription.GetContract(typeof(IOrderService));
  13:             ServiceEndpoint endpoint1 = new ServiceEndpoint(contract, new WS2007HttpBinding(), 
  14:                 new EndpointAddress("http://127.0.0.1/orderservice"));
  15:             ServiceEndpoint endpoint2 = new ServiceEndpoint(contract, new NetTcpBinding(),
  16:                new EndpointAddress("net.tcp://127.0.0.1/orderservice"));
  17:             XmlQualifiedName serviceName = new XmlQualifiedName("OrderService", "http://www.artech.com/services/");
  18:             WsdlExporter exporter = new WsdlExporter();
  19:             exporter.ExportEndpoints(new ServiceEndpoint[] { endpoint1, endpoint2 }, serviceName);
  20:             MetadataSet metadata = exporter.GetGeneratedMetadata();
  21:             using (XmlWriter writer = new XmlTextWriter("metadata.xml", Encoding.UTF8))
  22:             {
  23:                 metadata.WriteTo(writer);
  24:             }
  25:             Process.Start("metadata.xml");
  26:         }
  27:     }
  28: } 

由于本机采用IE作为开启XML文件默认的应用程序,当上面的代码成功执行后,包含有元数据的XML文件会通过IE打开。图2是运行后的截图,从图中我们可以看出导出的元数据由6个MetadataSection构成。所有MetadataSection的元数据方言(Dialect)集中在WSDL和XML Schema两种,其中基于XML Schema方言的MetadataSection描述了我通过数据契约定义的Order和OrderDetail类型的XML结构;基于Order类型的输入消息和输出消息的XML结构;以及所有CLR基元类型(Primary Type,比如int、double和DateTime等)。而所有基于WSDL方言的MetadataSection共同构建了一份反映服务的WSDL文档。该WSDL除了包含WSDL基本的5个元素之外,还包含通过WS2007HttpBinding和NetTcpBinding导出的一些WS-Policy策略断言。

2 通过IE查看导出的元数据

作者:蒋金楠
微信公众账号:大内老A
微博:www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
原文链接

WCF技术剖析之二十六:如何导出WCF服务的元数据(Metadata)[实现篇]相关推荐

  1. WCF技术剖析之二十八:自己动手获取元数据[附源代码下载]

    WCF技术剖析之二十八:自己动手获取元数据[附源代码下载] 原文:WCF技术剖析之二十八:自己动手获取元数据[附源代码下载] 元数据的发布方式决定了元数据的获取行为,WCF服务元数据架构体系通过Ser ...

  2. WCF技术剖析之二十九:换种不同的方式调用WCF服务[提供源代码下载]

    原文:WCF技术剖析之二十九:换种不同的方式调用WCF服务[提供源代码下载] 我们有两种典型的WCF调用方式:通过SvcUtil.exe(或者添加Web引用)导入发布的服务元数据生成服务代理相关的代码 ...

  3. WCF技术剖析之二十五: 元数据(Metadata)架构体系全景展现[WS标准篇]

    元数据实际上是服务终结点的描述,终结点由地址(Address).绑定(Binding)和契约(Contract)经典的ABC三要素组成.认真阅读过<WCF技术剖析(卷1)>的读者相对会对这 ...

  4. WCF技术剖析之二十: 服务在WCF体系中是如何被描述的?

    任何一个程序都需要运行于一个确定的进程中,进程是一个容器,其中包含程序实例运行所需的资源.同理,一个WCF服务的监听与执行同样需要通过一个进程来承载.我们将为WCF服务创建或指定一个进程的方式称为服务 ...

  5. [原创]WCF技术剖析之二十: 服务在WCF体系中是如何被描述的?

    任何一个程序都需要运行于一个确定的进程中,进程是一个容器,其中包含程序实例运行所需的资源.同理,一个WCF服务的监听与执行同样需要通过一个进程来承载.我们将为WCF服务创建或指定一个进程的方式称为服务 ...

  6. WCF技术剖析之二十七: 如何将一个服务发布成WSDL[基于HTTP-GET的实现](提供模拟程序)...

    WCF技术剖析之二十七: 如何将一个服务发布成WSDL[基于HTTP-GET的实现](提供模拟程序) 原文:WCF技术剖析之二十七: 如何将一个服务发布成WSDL[基于HTTP-GET的实现](提供模 ...

  7. WCF技术剖析之二十一:WCF基本异常处理模式[中篇]

    通过WCF基本的异常处理模式[上篇], 我们知道了:在默认的情况下,服务端在执行某个服务操作时抛出的异常(在这里指非FaultException异常),其相关的错误信息仅仅限于服务端可见,并不会被WC ...

  8. WCF技术剖析之二十三:服务实例(Service Instance)生命周期如何控制[中篇]

    在[第1篇]中,我们介绍了WCF关于实例管理一些基本的知识点,包括InstanceContext.InstanceContextMode.已经如何通过ServiceBehaviorAttribute应 ...

  9. WCF技术剖析之二十三:服务实例(Service Instance)生命周期如何控制[上篇](转)...

    http://www.cnblogs.com/artech/archive/2009/11/05/1596925.html 服务调用的目的体现在对某项服务功能的消费上,而功能的实现又定义在相应的服务类 ...

最新文章

  1. 第十六届智能车竞赛比赛进行中 - 参赛队员提出的问题
  2. 民生银行 IT运维故障管理 可视化案例
  3. UVA-804 模拟
  4. eclipse报告Plugin execution not covered by lifecycle configuration
  5. 26. 左旋转字符串
  6. 我发誓:下辈子再也不学JavaScript了
  7. 数据结构之串:串的模式匹配
  8. 【opencv学习】Fast算法进行角点检测
  9. C++的使用Lambda
  10. 纳英特九宫医疗机器人编程_机器人大赛|我校王子航、阮云天成功进入世界机器人华东赛区决赛...
  11. 公开封尘已久的即时通讯源码(转)
  12. 内存之私有sql区和共享sql区
  13. exception e 是泛类吗_Spring异步编程 | 你的@Async就真的异步吗?异步历险奇遇记
  14. 最新:斐讯K3千兆无线路由器刷官改版固件的详细图文教程
  15. Python超级码力在线编程大赛初赛题解
  16. 软件测试理论知识基础详细解说—总结
  17. (15.1.16)项目管理简述
  18. 学完计算机专业英语感受,计算机专业英语感想
  19. 用pip给python安装matplotlib库-windows
  20. PSV 黑商店 pkgj 无法刷新列表 显示HttpError 的解决办法

热门文章

  1. Visual Studio 中常用的快捷键
  2. SplObserver观察者模式
  3. 微软将本地版Exchange、SharePoint和Skype 纳入漏洞奖励计划
  4. 谷歌 Nest 和 Fitbit 漏洞奖励翻番
  5. Facebook Messenger 被曝漏洞,可导致恶意软件获得持续访问权限(详细分析)
  6. GitHub 2019年漏洞奖励计划最值得回顾的2个精彩 bug
  7. systemd 与 sysVinit 彩版对照表
  8. [Android Studio] Android Studio如何快速生成get,set,tostring,构造函数
  9. 黑加仑妞 使用vue+flask做全栈开发的全过程(实现前后端分离)
  10. 通用Makefile模板