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两种协议的元数据发布的。


作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
前端开发
WCF更新服务引用报错的原因之一
WCF更新服务引用报错的原因之一
|
Oracle 关系型数据库 API
C# LIS检验系统源码,接口技术:RESTful API + Http+WCF
LIS检验系统一种专门用于医院化验室的计算机系统,它致力于提高医院化验室的工作效率和检测准确率。LIS系统由多个子系统组成,包括样本管理系统、质控系统、检验结果管理系统、报告管理系统等。体系结构:Client/Server架构 SaaS模式 客户端:WPF+Windows Forms 服务端:C# +.Net 数据库:Oracle 接口技术:RESTful API + Http+WCF
118 2
|
C# 数据安全/隐私保护
c#如何创建WCF服务到发布(SqlServer版已经验证)
c#如何创建WCF服务到发布(SqlServer版已经验证)
79 0
|
安全 数据库连接 数据库
WCF服务创建到发布(SqlServer版)
在本示例开始之前,让我们先来了解一下什么是wcf? wcf有哪些特点? wcf是一个面向服务编程的综合分层架构。该架构的项层为服务模型层。 使用户用最少的时间和精力建立自己的软件产品和外界通信的模型。它使得开发者能够建立一个跨平台的安全、可信赖、事务性的解决方案。且能与已有系统兼容写作。 简单概括就是:一组数据通信的应用程序开发接口。
116 0
|
C++
WCF基础教程(二)——解析iis8和iis8.5+VS2013发布wcf服务问题
WCF基础教程(二)——解析iis8和iis8.5+VS2013发布wcf服务问题
143 0
WCF基础教程(二)——解析iis8和iis8.5+VS2013发布wcf服务问题
WCF使用纯代码的方式进行服务寄宿
服务寄宿的目的是为了开启一个进程,为WCF服务提供一个运行的环境。通过为服务添加一个或者多个终结点,使之暴露给潜在的服务消费,服务消费者通过匹配的终结点对该服务进行调用,除去上面的两种寄宿方式,还可以以纯代码的方式实现服务的寄宿工作。
895 0
|
安全 网络架构
消息(7)——WCF编程模型中控制消息(1)绑定,契约
WCF服务要通过终结点来进行通信,终结点三大构成元素:ABC,其中的B,binding是重中之重,它解决了在消息交换过程中的编码,传输协议,安全等问题。 绑定是分层的,一个绑定对象对应一组有序的绑定元素的集合。
772 0
|
Windows
WCF服务寄宿到IIS
一.WCF简介: Windows Communication Foundation(WCF)是由微软开发的一系列支持数据通信的应用程序框架,可以翻译为Windows 通讯开发平台。整合了原有的windows通讯的 .net Remoting,WebService,Socket的机制,并融合有HTTP和FTP的相关技术。
1101 0
WCF服务自我寄宿
WCF服务的寄宿方式 WCF寄宿方式是一种非常灵活的操作,可以寄宿在各种进程之中,常见的寄宿有: IIS服务、Windows服务、Winform程序、控制台程序中进行寄宿,从而实现WCF服务的运行,为调用者方便、高效提供服务调用。
1038 0