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

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

一、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个元素之外,还包含通过WS2007HttpBindingNetTcpBinding导出的一些WS-Policy策略断言。

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

作者:Artech
出处:http://artech.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

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

  1. WCF技术剖析之二十六:如何导出WCF服务的元数据(Metadata)[扩展篇]

    原文:WCF技术剖析之二十六:如何导出WCF服务的元数据(Metadata)[扩展篇] 通过<实现篇>对WSDL元素和终结点三要素的之间的匹配关系的介绍,我们知道了WSDL的Binding ...

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

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

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

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

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

    原文:WCF技术剖析之二十五: 元数据(Metadata)架构体系全景展现[元数据描述篇] 在[WS标准篇]中我花了很大的篇幅介绍了WS-MEX以及与它相关的WS规范:WS-Policy.WS-Tra ...

  5. WCF技术剖析之二十四: ServiceDebugBehavior服务行为是如何实现异常的传播的?

    原文:WCF技术剖析之二十四: ServiceDebugBehavior服务行为是如何实现异常的传播的? 服务端只有抛出FaultException异常才能被正常地序列化成Fault消息,并实现向客户 ...

  6. WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇]

    原文:WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇] 在[上篇]中,我们分别站在消息交换和编程的角度介绍了SOAP Fault和FaultException异常.在服务执行过 ...

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

    原文:WCF技术剖析之二十: 服务在WCF体系中是如何被描述的? 任何一个程序都需要运行于一个确定的进程中,进程是一个容器,其中包含程序实例运行所需的资源.同理,一个WCF服务的监听与执行同样需要通过 ...

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

    原文:WCF技术剖析之二十七: 如何将一个服务发布成WSDL[基于HTTP-GET的实现](提供模拟程序) 基于HTTP-GET的元数据发布方式与基于WS-MEX原理类似,但是ServiceMetad ...

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

    原文:WCF技术剖析之二十七: 如何将一个服务发布成WSDL[基于WS-MEX的实现](提供模拟程序) 通过<如何将一个服务发布成WSDL[编程篇]>的介绍我们知道了如何可以通过编程或者配 ...

随机推荐

  1. 自动分组+合并完整的sql脚本

    BEGIN#前提:指定字符串长度为8字符定长#逻辑:循环8次,比对2个字符串相同索引位置下的数值大小,并取结果最大值.#示例:merge1(输入参数source1,输入参数source2,输出结果re ...

  2. 关于SOQL(一)

    SOQL 是Salesforce中的查询语言,他的全称是Salesforce Object Query Language. 从字面上就能够看出,这个语言是一种基于对象的查询语言. 在Salesforc ...

  3. 解决:Visual Assist X 不支持HTML、Javascript等提示

    Visual Assist X 安装后,不能进行javascript hmtl提示,只有回到老版本才行.这个问题折腾了老久,才给解决了. 记录下来,以便于网友和自己使用. 问题原因: Visual A ...

  4. JavaSE学习总结第15天_集合框架1

      15.01 对象数组的概述和使用 public class Student { // 成员变量 private String name; private int age; // 构造方法 publ ...

  5. java的for循环问题的解决,以及安卓中ListView插入数据的问题

    package test.testdemo; import org.springframework.jdbc.core.JdbcTemplate; import com.util.Pub; publi ...

  6. JDBC_获取插入记录的主键值

    <span style="font-size:24px;">package src.com.JDBC2DAO.java; import static org.junit ...

  7. 第2章 Python基础语法 -- 数据类型

    2.2数据类型 变量存储在内存中的值.这就意味着在创建变量时会在内存中开辟一个空间.基于变量的数据类型,解释器会分配指定内存,并决定什么数据可以被存储在内存中. 2.2.1 标准数据类型 在内存中存储 ...

  8. Qt学习 之 多线程程序设计(QT通过三种形式提供了对线程的支持)

    QT通过三种形式提供了对线程的支持.它们分别是, 一.平台无关的线程类 二.线程安全的事件投递 三.跨线程的信号-槽连接. 这使得开发轻巧的多线程Qt程序更为容易,并能充分利用多处理器机器的优势.多线 ...

  9. mybatis通用DAO

    扫扫关注"茶爸爸"微信公众号 坚持最初的执着,从不曾有半点懈怠,为优秀而努力,为证明自己而活. 回复:茶爸爸了解他这个人!! 花了几天的时间研究了一下mybatis的源代码,觉得这 ...

  10. Sicily-1024

    一. 题意: 有n个节点,n-1条边,并且任意两个节点都连通.模拟一下,实际上是一棵树的便利,求从特定根节点出发最长路径的值.这里用了广搜. 二. 每个节点只有两条邻接边,每个节点用一个vector来 ...