原文: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. 【SqlServer数据类型、C#数据类型、SqlDbType】对应关系及转换

    // sql server数据类型(如:varchar)// 转换为SqlDbType类型public static SqlDbType SqlTypeString2SqlType(string sq ...

  2. Java基础--finalize()方法

    原理: 一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法,并在下一次垃圾回收动作发生时,才会真正回收对象占用的内存. 用途: 1)释放通过某种创建对象方式以外的方式为对 ...

  3. DevExpress ASP.NET 使用经验谈(7)-ASPxTreeList控件使用

    这一节,将介绍ASPxTreeList控件的使用,首先,我们增加一个标准地址库表AddressGB, 建表语句如下: CREATE TABLE [dbo].[AddressGB]( [Code] [v ...

  4. POJ 2250 Compromise(LCS)

    POJ 2250 Compromise(LCS)解题报告 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=87125#proble ...

  5. Longest Palindromic Substring - 一题多解

    题意是寻找一个字符串的最大回文字串,最简单的是n3方的算法,由于字符串最大长度为1000,所以这个方法很危险而且不科学. 紧接着想到的是一个n方的算法:回文子串是从中间向两边产生的,那么对于每个字符考 ...

  6. java代码获取ip地址

    public class IpTool { public static void main(String[] args) { IpTool ipTool=new IpTool(); System.ou ...

  7. HTML5 DTD

    HTML5/HTML 4.01/XHTML 元素和有效的 DTD 下面的表格列出了所有的 HTML5/HTML 4.01/XHTML 元素,以及它们会出现在什么文档类型 (DTD) 中: 标签 HTM ...

  8. oracle 10g函数大全--分析函数

    oracle分析函数--SQL*PLUS环境 一.总体介绍 12.1 分析函数如何工作 语法 FUNCTION_NAME(<参数>,…) OVER (<PARTITION BY 表达 ...

  9. cocos2dx进阶学习之瓦片地图编辑器

    之前学习了瓦片地图类,现在我们来学习下瓦片地图制作工具 这个是开源的工具,可以从网上下载,下面我们演示下怎么做地图 步骤1 将需要用到的图片放到一个目录下,比如我机器上就是d:\tiled,这些图片是 ...

  10. cocos2d-x游戏开发系列教程-超级玛丽06-CMGameScene

    背景 在CMMenuScene中,当用户点击开始游戏时,导演让场景进入到CMGameScene 头文件 class CMGameScene : public cocos2d::CCLayer,publ ...