原文:WCF技术剖析之二十七: 如何将一个服务发布成WSDL[编程篇]

对于WCF服务端元数据架构体系来说,通过MetadataExporter将服务的终结点导出成MetadataSet(参考《如何导出WCF服务的元数据》),仅仅是完成了一半的工作。被成功导出的以MetadataSet对象表示的元数据需要最终作为可被访问的网络资源发布出来,才能被服务消费者获取,进而有效地帮助他们进行服务调用。元数据的发布最终是通过ServiceMetadataBehavior这样一个服务行为实现的,我们先来认识一下ServiceMetadataBehavior

一、 元数据发布的实现者:ServiceMetadataBehavior

ServiceMetadataBehavior是一个实现了IServiceBehavior的服务行为,它实现了基于如下两种协议的元数据发布模式:

  • HTTP-GET:采用HTTP协议的Get操作,向元数据目标地址发送HTTP请求,并以查询字符串(QueryString)的形式表示相应的查询参数。元数据最终以HTTP回复的形式返回;
  • WS-MEX:元数据提供者按照WS-MEX规范创建终结点发布元数据,元数据消费者创建同样基于WS-MEX的终结点与之交互,并最终通过SOAP的形式获取元数据。关于WS-MEX,可以参考我的文章《元数据(Metadata)架构体系全景展现[WS标准篇]

我们首先通过如下得代码来看看ServiceMetadataBehavior的定义,ServiceMetadataBehavior实现IServiceBehavior接口,并将所有发布元数据的行为定义在ApplyDispatchBehavior方法中。

   1: public class ServiceMetadataBehavior : IServiceBehavior

   2: {

   3:    

   4:     //其他成员

   5:     void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters);

   6:     void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase);

   7:     void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase);

   8:  

   9:     public Uri ExternalMetadataLocation { get; set; }    

  10:  

  11:     //HTTP

  12:     public bool HttpGetEnabled { get; set; }

  13:     public Uri HttpGetUrl { get; set; }

  14:     public Binding HttpGetBinding { get; set; }

  15:  

  16:     //HTTPS

  17:     public bool HttpsGetEnabled { get; set; }

  18:     public Binding HttpsGetBinding { get; set; }

  19:     public Uri HttpsGetUrl { get; set; }

  20:  

  21:     public MetadataExporter MetadataExporter { get; set; }

  22: }

ServiceMetadataBehavior定义了一系列的属性用于控制具体的元数据发布行为,其中绝大部分是基于HTTP-GET发布模式的。ExternalMetadataLocation表示返回给客户端的一个外部元数据地址,可以是绝对地址,也可以是基于HttpGetUrl或者HttpsGetUrl表述的相对地址;基于HTTP-GET的元数据发布同时支持HTTP和HTTPS两种形式,Http(s)GetEnabled是控制是否允许基于HTTP(s)进行元数据发布的开关,Http(s)GetUrl和Http(s)GetBinding这指定了采用的地址和绑定;MetadataExporter属性表示的MetadataExporter对象用于进行元数据的导出,默认为WsdlExporter

你可以通过配置的方式来设置除MetadataExporter之外的所有ServiceMetadataBehavior的属性,此外,WCF还提供给你一些额外的配型项供你更好地控制元数据的发布行为。对于WCF的开发者或者实施者来说,当你没有一份完备的文档指导你进行基于服务行为或者终结点行为的配置时,你可以查看该行为对应的BehaviorExtensionElement的定义获取与该行为相关的所有配置信息。ServiceMetadataBehavior相关的配置项全部定义在ServiceMetadataPublishingElement中,下面给出了ServiceMetadataPublishingElement的定义:

   1: public sealed class ServiceMetadataPublishingElement : BehaviorExtensionElement

   2: {

   3:     //其他成员

   4:     public override Type BehaviorType { get; }

   5:     [ConfigurationProperty("externalMetadataLocation")]

   6:     public Uri ExternalMetadataLocation { get; set; }

   7:  

   8:     //HTTP

   9:     [ConfigurationProperty("httpGetEnabled", DefaultValue = false)]

  10:     public bool HttpGetEnabled { get; set; }

  11:     [ConfigurationProperty("httpGetUrl")]

  12:     public Uri HttpGetUrl { get; set; }

  13:     [StringValidator(MinLength=0), ConfigurationProperty("httpGetBinding", DefaultValue="")]

  14:     public string HttpGetBinding { get; set; }

  15:     [ConfigurationProperty("httpGetBindingConfiguration", DefaultValue=""), StringValidator(MinLength=0)]

  16:     public string HttpGetBindingConfiguration { get; set; }

  17:  

  18:     //HTTPS

  19:     [ConfigurationProperty("httpsGetEnabled", DefaultValue = false)]

  20:     public bool HttpsGetEnabled { get; set; }

  21:     [ConfigurationProperty("httpsGetUrl")]

  22:     public Uri HttpsGetUrl { get; set; }

  23:     [StringValidator(MinLength=0), ConfigurationProperty("httpsGetBinding", DefaultValue="")]

  24:     public string HttpsGetBinding { get; set; }

  25:     [StringValidator(MinLength=0), ConfigurationProperty("httpsGetBindingConfiguration", DefaultValue="")]

  26:     public string HttpsGetBindingConfiguration { get; set; }

  27:  

  28:     [ConfigurationProperty("policyVersion", DefaultValue="Default"), TypeConverter(typeof(PolicyVersionConverter))]

  29:     public PolicyVersion PolicyVersion { get; set; }

  30: }

通过对ServiceMetadataPublishingElement的定义我们可以看出:我们可以通过除MetadataExporter之外的所有ServiceMetadataBehavior的属性,还可以通过policyVersion配置向指定具体采用的WS-Policy的版本。下面是一个ServiceMetadataBehavior配置的例子:

   1: <?xml version="1.0" encoding="utf-8" ?>

   2: <configuration>

   3:     <system.serviceModel>

   4:         <services>

   5:             <service behaviorConfiguration="MetadataPublishBehavior" name=" Artech.Services.CalculatorService">

   6:                 <endpoint address="http://127.0.0.1:3721/calcuulatorservice"

   7:                     binding="basicHttpBinding" bindingConfiguration="" contract=" Artech.Contracts.ICalculator" />                

   8:             </service>

   9:         </services>

  10:  

  11:       <behaviors>

  12:         <serviceBehaviors>

  13:           <behavior name="MetadataPublishBehavior">

  14:             <serviceMetadata externalMetadataLocation="http://127.0.1/mex/calculatorservice"

  15:                 httpGetEnabled="true" httpGetUrl="http://127.0.0.1/calculatorservice/mex"

  16:                 httpsGetEnabled="true" httpsGetUrl="https://127.0.0.1/calculatorservice/mex"

  17:                 policyVersion="Policy15" />

  18:           </behavior>

  19:         </serviceBehaviors>

  20:       </behaviors>

  21: </system.serviceModel>

  22: </configuration>

如果你希望通过WS-MEX的方式进行元数据的发布,你需要为服务添加一个基于WS-MEX的终结点。基于WS-MEX的终结点和一般意义上的终结点一样由地址、绑定和契约三部分组成。其中,地址表示发布元数据的目标地址,而绑定和契约因为需要按照WS-MEX规范进行消息的交换,所以对绑定和契约具有特殊的要求。在具体对MEX终结点展开介绍之前,我们不妨先来看看如何通过配置的方式为服务添加MEX终结点:

   1: <?xml version="1.0" encoding="utf-8" ?>

   2: <configuration>

   3:     <system.serviceModel>

   4:         <services>

   5:             <service name="Artech.Services.CalculatorService">

   6:                 <endpoint address="http://127.0.0.1:3721/calcuulatorservice"

   7:                     binding="basicHttpBinding" bindingConfiguration="" contract="Artech.Contracts.ICalculator" />

   8:                 <endpoint address="http://127.0.0.1:3721/calcuulatorservice/mex"

   9:                     binding="mexHttpBinding" bindingConfiguration="" contract="IMetadataExchange" />               

  10:             </service>

  11:         </services> 

  12:     </system.serviceModel>

  13: </configuration>

二、MEX 终结点有何不同?

我们通过为服务添加基于WS-MEX的终结点(以下简称MEX终结点)实现支持WS-MEX的元数据发布方式。总的来说,MEX终结点和一般意思上的终结点并没有本质的不同,也是由地址、绑定和契约三要素构成。但是,为了支持WS-MEX规定的消息交换模式和请求/回复消息的结构,对契约和绑定具有一些特殊的要求,先来看看MEX终结点的契约。

1、MEX终结点的契约:IMetadataExchange

从上面给出的基于MEX终结点的配置中,我们可以看到该终结点的契约被配置成“IMetadataExchange”。实际上IMetadataExchange是WCF内部定义的一个特殊服务契约接口,定义在System.ServiceModel.Description命名空间下,下面是IMetadataExchange的定义:

   1: [ServiceContract(ConfigurationName = "IMetadataExchange", Name = "IMetadataExchange", Namespace = "http://schemas.microsoft.com/2006/04/mex")]

   2: public interface IMetadataExchange

   3: {

   4:      [OperationContract(Action = "http://schemas.xmlsoap.org/ws/2004/09/transfer/Get", ReplyAction = "http://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse", AsyncPattern = true)]

   5:     IAsyncResult BeginGet(Message request, AsyncCallback callback, object state);

   6:     Message EndGet(IAsyncResult result);

   7:     [OperationContract(Action = "http://schemas.xmlsoap.org/ws/2004/09/transfer/Get", ReplyAction = "http://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse")]

   8:     Message Get(Message request);

   9: }

从定义可以看出,IMetadataExchange实际上仅仅包含一个Get服务操作,其中Get方法是正常的同步模式服务操作,而BeginGet/EndGet是按照标准的异步操作模式对Get服务操作的定义(关于异步服务操作模式,在《WCF技术剖析(卷1)》的第4章有详细的介绍)。

进一步分析IMetadataExchange的定义,由于通过ServiceContractAttribute特性将ConfigurationName属性设定成“IMetadataExchange”,这也是为何在进行MEX终结点的配置的时候,契约可以直接配置成“IMetadataExchange”,而不是“System.ServiceModel.Description. IMetadataExchange”。

再来看看Get操作,通过OperationContractAttribute特性将Action和ReplyAction设置成了http://schemas.xmlsoap.org/ws/2004/09/transfer/Gethttp://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse,如果读者《元数据(Metadata)架构体系全景展现[WS标准篇]》WS-Transfer相关介绍还有印象的话,应该知道它们就是WS-Transfer Get请求和回复SOAP消息对应的Action的值。在介绍WS—MEX的时候,我们提到过WS-MEX支持两种形式的元数据获取方式:WS-Transfer Get操作请求和Get Metadata操作请求。从这里可以看出,WCF采用的是基于WS-Transfer Get操作的元数据请求方式。

2、MEX终结点的绑定:MetadataExchangeBindings

WCF专门为MEX终结点定制了一系列的绑定,以实现对不同的网络传输协议(HTTP、HTTPS、TCP或者Named Pipe)的支持。这些定制的MEX绑定定义在MetadataExchangeBindings静态类中,你可以通过相应CreateMexXxxBinding方法创建基于某种传输协议的绑定。MetadataExchangeBindings的定义如下:

   1: public static class MetadataExchangeBindings

   2: {

   3:     //其他成员

   4:     public static Binding CreateMexHttpBinding();

   5:     public static Binding CreateMexHttpsBinding();

   6:     public static Binding CreateMexTcpBinding();   

   7:     public static Binding CreateMexNamedPipeBinding(); 

   8: }

如果你采用编程的方式为服务添加MEX终结点,那么你可以直接借助MetadataExchangeBindings创建相应的MEX绑定。如果采用配置的方式,仅仅需要将终结点的binding配置成:mexHttpBinding、mexHttpsBinding、mexTcpBinding和mexNamedPipeBinding即可,具体配置可以参考下面:

   1: <?xml version="1.0" encoding="utf-8" ?>

   2: <configuration>

   3:     <system.serviceModel>

   4:         <services>

   5:             <service behaviorConfiguration="MetadataPublishBehavior" name=" Artech.Services.CalculatorService">

   6:                 <endpoint address="http://127.0.0.1:3721/calcuulatorservice"

   7:                     binding="basicHttpBinding" bindingConfiguration="" contract="Artech.Contracts.ICalculator" />                

   8:                 <endpoint address="http://127.0.0.1/calculatorservice/mex" binding="mexHttpBinding" contract="IMetadataExchange" />

   9:                 <endpoint address="https://127.0.0.1/calculatorservice/mex" binding="mexHttpsBinding" contract="IMetadataExchange" />

  10:                 <endpoint address="net.tcp://127.0.0.1/calculatorservice/mex"                    binding="mexTcpBinding" contract="IMetadataExchange" />

  11:                 <endpoint address="net.pipe://127.0.0.1/calculatorservice/mex"                    binding="mexNamedPipeBinding" contract="IMetadataExchange" />

  12:             </service>

  13:         </services>

  14:     </system.serviceModel>

  15: </configuration>

下一篇中,我们将会讨论ServiceMetadataBehavior在内部是如何实现基于HTTP-GET和WS-MEX两种协议的元数据发布的。

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

WCF技术剖析之二十七: 如何将一个服务发布成WSDL[编程篇]的更多相关文章

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

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

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

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

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

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

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

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

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

    原文:WCF技术剖析之二十六:如何导出WCF服务的元数据(Metadata)[实现篇] 元数据的导出就是实现从ServiceEndpoint对象向MetadataSet对象转换的过程,在WCF元数据框 ...

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

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

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

    原文:WCF技术剖析之二十一:WCF基本异常处理模式[中篇] 通过WCF基本的异常处理模式[上篇], 我们知道了:在默认的情况下,服务端在执行某个服务操作时抛出的异常(在这里指非FaultExcept ...

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

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

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

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

随机推荐

  1. iOS开发 点击跳转到App Store 或者 点击按钮去评价

    //跳转到应用页面 NSString *str = [NSString stringWithFormat:@"http://itunes.apple.com/us/app/id%d" ...

  2. jquery 上下滑动效果

    <script type="text/javascript"> var myar = setInterval('AutoScroll(".li_gundong ...

  3. Python学习之路——类

    类: 类是将抽象的实物进行的划分. 在现实世界中如果我们将: 人类包含:男人.女人.孩子.老人等动物类包含:小猫.小狗.小兔子等 在代码世界中我也可以分类,例如将相同功能的代码放到一起,这就是分类. ...

  4. 教你怎么用Mono Cecil - 动态注入 (注意代码的注释)

    原文 教你怎么用Mono Cecil - 动态注入 (注意代码的注释) 使用 Mono Cecil 进行反编译:using Mono.Cecil; using Mono.Cecil.Cil; //.. ...

  5. BZOJ 1611: [Usaco2008 Feb]Meteor Shower流星雨

    1611: [Usaco2008 Feb]Meteor Shower流星雨 Description 去年偶们湖南遭受N年不遇到冰冻灾害,现在芙蓉哥哥则听说另一个骇人听闻的消息: 一场流星雨即将袭击整个 ...

  6. [置顶] ios 360度旋转效果demo

    demo功能:用UIimageView实现360度旋转效果. demo说明:iPhone6.1 测试成功.主要代码在:FVImageSequence.m中.在touchesMoved事件中,通过替换U ...

  7. hdu4597 Play Game

    Play Game Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others) Total Sub ...

  8. 《Android第一行代码》笔记

    学习Android开发差点儿相同有两年时间了.期间也做了大大小小的一些项目.近来抽出闲暇想把Android基础强化一下,之前在网上看到了郭霖郭大神的几篇博客.从中受益不少.于是花了近一周时间看完了郭神 ...

  9. android 上传文件

    android对于上传文件,还是非常easy的,和java里面的上传都是一样的,基本上都是熟悉操作输出流和输入流!另一个特别重要的就是须要一些content-type这些參数的配置!  假设这些都弄好 ...

  10. JavaScript 高级程序设计(第3版)笔记——chapter3:基本概念(函数部分)

    3.7函数 3.7.1 理解参数 ECMAScript 函数不介意传递进来多个参数,也不在乎传递进来的参数是什么数据类型.因为在 ECMAScript 中的参数在内部是用一个数组来表示的.在函数体内可 ...