zoukankan      html  css  js  c++  java
  • Chapter 1.4:WCF实践 元数据详解

    1. 源码下载

    下载地址:https://files.cnblogs.com/tianzhiliang/WCF.Chapter1.ServiceFactory.rar

    2. 元数据简介

      服务有两种方案可以发布自己的元数据。一种是基于 HTTP-GET 协议提供元数据,另一种是使用专门的终结点的方式。

      WCF能够为服务自动提供基于 HTTP-GET 的元数据,但需要显式地添加服务行为(Behavior)以支持这一功能。服务行为属于服务的本地特性,例如是否需要基于 HTTP-GET 交换元数据,就是一种服务行为。

      我们可以通过编程方式或管理配置方式添加行为,通过管理配置方式添加行为如下所示:

    <system.serviceModel>
    <services>
    <service name = "MyService" behaviorConfiguration = "MEXGET">
    <host>
    <baseAddresses>
    <add baseAddress = "http://localhost:8000/"/>
    </baseAddresses>
    </host>
    ...
    </service>
    <service name = "MyOtherService" behaviorConfiguration = "MEXGET">
    <host>
    <baseAddresses>
    <add baseAddress = "http://localhost:8001/"/>
    </baseAddresses>
    </host>
    ...
    </service>
    </services>
    <behaviors>
    <serviceBehaviors>
    <behavior name = "MEXGET">
    <serviceMetadata httpGetEnabled = "true"/>
    </behavior>
    </serviceBehaviors>
    </behaviors>
    </system.serviceModel><system.serviceModel>
    <services>
    <service name = "MyService" behaviorConfiguration = "MEXGET">
    <host>
    <baseAddresses>
    <add baseAddress = "http://localhost:8000/"/>
    </baseAddresses>
    </host>
    ...
    </service>
    <service name = "MyOtherService" behaviorConfiguration = "MEXGET">
    <host>
    <baseAddresses>
    <add baseAddress = "http://localhost:8001/"/>
    </baseAddresses>
    </host>
    ...
    </service>
    </services>
    <behaviors>
    <serviceBehaviors>
    <behavior name = "MEXGET">
    <serviceMetadata httpGetEnabled = "true"/>
    </behavior>
    </serviceBehaviors>
    </behaviors>
    </system.serviceModel>

      通过编程方式添加行为如下所示:

    ServiceHost host = new ServiceHost(typeof(MyService));
    ServiceMetadataBehavior metadataBehavior;
    metadataBehavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
    if(metadataBehavior == null)
    {
        metadataBehavior = new ServiceMetadataBehavior();
        metadataBehavior.HttpGetEnabled = true;
        host.Description.Behaviors.Add(metadataBehavior);
    }
    host.Open();

      一旦启用了基于 HTTP-GET 的元数据交换,在浏览器中就可以通过 HTTP 基地址(如果存在)进行访问。如果一切正确,就会获得一个确认页面,告知开发者已经成功托管了服务。确认页面与 IIS 托管无关,即使使用自托管,我们也可以使用浏览器定位服务地址。

    3. 元数据交换终结点

      元数据交换终结点是一种特殊的终结点,有时候又被称为 MEX 终结点。服务能够根据元数据交换终结点发布自己的元数据,如图 1.4-1 在通常情况下并不需要在设计图中显示元数据交换终结点。

      WCF 自动地为服务宿主提供了 IMetadataExchange 接口的实现,公开元数据交换终结点。我们只需要指定使用的地址和绑定,以及添加服务元数据行为。对于绑定,WCF 提供了专门的基于 HTTP、HTTPS、TCP 和 IPC 协议的绑定传输元素。对于地址,我们可以提供完整的地址,或者使用任意一个注册了的基地址。没有必要启用 HTTP-GET 选项,但是即使启用了也不会造成影响。

      通过管理方式配置MEX终结点,如下所示:

    <services>
    <service name = "MyService" behaviorConfiguration = "MEX">
    <host>
    <baseAddresses>
    <add baseAddress = "net.tcp://localhost:8001/"/>
    <add baseAddress = "net.pipe://localhost/"/>
    </baseAddresses>
    </host>
    <endpoint
    address  = "MEX"
    binding  = "mexTcpBinding"
    contract = "IMetadataExchange"
    />
    <endpoint
    address  = "MEX"
    binding  = "mexNamedPipeBinding"
    contract = "IMetadataExchange"
    />
    <endpoint
    address  = "http://localhost:8000/MEX"
    binding  = "mexHttpBinding"
    contract = "IMetadataExchange"
    />
    </service>
    </services>
    <behaviors>
    <serviceBehaviors>
    <behavior name = "MEX">
    <serviceMetadata/>
    </behavior>
    </serviceBehaviors>
    </behaviors>

      通过编程方式配置MEX终结点,WCF并没有为元数据交换终结点提供专门的绑定类型。为此,我们需要创建定制绑定。定制绑定使用了与之匹配的传输绑定元素(即 BindingElement 类型),然后将绑定元素对象作为构造函数的参数,传递给定制绑定实例。最后,调用宿主的 AddServiceEndpoint() 方法,参数值分别为地址、定制绑定与 IMetadataExchange契约类型。注意,在添加终结点之前,必须校验元数据行为是否存在。如下所示:

    BindingElement bindingElement = new TcpTransportBindingElement();
    CustomBinding binding = new CustomBinding(bindingElement);
    Uri tcpBaseAddress = new Uri("net.tcp://localhost:9000/");
    ServiceHost host = new ServiceHost(typeof(MyService),tcpBaseAddress);
    ServiceMetadataBehavior metadataBehavior;
    metadataBehavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
    if(metadataBehavior == null)
    {
        metadataBehavior = new ServiceMetadataBehavior();
        host.Description.Behaviors.Add(metadataBehavior);
    }
    host.AddServiceEndpoint(typeof(IMetadataExchange),binding,"MEX");
    host.Open();
    

    4. 通用 ServiceHost 扩展类

    using System;
    using System.Linq;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.Diagnostics;
    
    namespace WCF.Chapter1.ServiceFactory.Host
    {
        public class ServiceHost<T> : ServiceHost
        {
            public ServiceHost() :
                base(typeof(T))
            { }
    
            public ServiceHost(params Uri[] baseAddresses) :
                base(typeof(T), baseAddresses)
            { }
    
            public bool HasMexEndpoint
            {
                get
                { 
                    return Description.Endpoints.Any(endpoint => endpoint.Contract.ContractType == typeof(IMetadataExchange));
                }
            }
    
            public void AddAllMexEndpoints()
            {
                Debug.Assert(HasMexEndpoint == false);
    
                foreach (Uri baseAddress in BaseAddresses)
                {
                    BindingElement bindingElement = null;
                    switch (baseAddress.Scheme)
                    {
                        case "net.tcp":
                        {
                            bindingElement = new TcpTransportBindingElement();
                            break;
                        }
                        case "net.pipe":
                        {
                            bindingElement = new NamedPipeTransportBindingElement();
                            break;
                        }
                        case "http":
                        {
                            bindingElement = new HttpTransportBindingElement();
                            break;
                        }
                        case "https":
                        {
                            bindingElement = new HttpsTransportBindingElement();
                            break;
                        }
                    }
    
                    if (bindingElement != null)
                    {
                        Binding binding = new CustomBinding(bindingElement);
                        AddServiceEndpoint(typeof(IMetadataExchange), binding, "MEX");
                    }
                }
            }
    
            public bool EnableMetadataExchange
            {
                set
                {
                    if (State == CommunicationState.Opened)
                    {
                        throw new InvalidOperationException("Host is already opened !");
                    }
    
                    ServiceMetadataBehavior metadataBehavior;
                    metadataBehavior = Description.Behaviors.Find<ServiceMetadataBehavior>();
                    if (metadataBehavior == null)
                    {
                        metadataBehavior = new ServiceMetadataBehavior();
                        metadataBehavior.HttpGetEnabled = value;
                        Description.Behaviors.Add(metadataBehavior);
                    }
    
                    if (value == true)
                    {
                        if (HasMexEndpoint == false)
                        {
                            AddAllMexEndpoints();
                        }
                    }
                }
    
                get
                {
                    ServiceMetadataBehavior metadataBehavior;
                    metadataBehavior = Description.Behaviors.Find<ServiceMetadataBehavior>();
                    if (metadataBehavior == null)
                    {
                        return false;
                    }
                    return metadataBehavior.HttpGetEnabled;
                }
            }
        }
    }

      EnableMetadataExchange通过判断 CommunicationObject 基类的 State 属性值,确保宿主没有被打开。如果在配置文件中没有找到元数据行为,EnableMetadataExchange不会重写 配置文件中的配置值,而只是将 value 赋给新建的元数据行为对象 metadatabehavior 的 HttpGetEnabled 属性。读取 EnableMetadataExchange 的值时,属性首先会检查值是否已经配置。 如果没有配置元数据行为,则返回 false ;否则返回它的HttpGetEnabled 值。HasMexEndpoint 属性将匿名方法赋给 Predicate泛型委托。匿名方法负责检查给定终结点的契约是否属于 IMetadataExchange 类型。然后,遍历集合中的每个元素并调用 Predicate 泛型委托对象mexEndPoint,如果集合中的任意一个元素符合 Predicate 指定的比较条件,则返回 tru e,否则返回 f alse 。AddAllMexEnd-Points()方法会遍历 BaseAddresses 集合。根据基地址的样式,创建匹配的 MEX 传输绑定元素,然后再创建一个定制绑定,并将它传入到 AddServiceEndpoint() 中。

  • 相关阅读:
    求助:可以使用任何编程工具做成一个控件或组件,使得在VB中能调用并得到摄像头的参数及图片。
    作为软件工程师,你必须知道的20个常识
    继续C#开发or转做产品
    65行 JavaScript 代码实现 Flappy Bird 游戏
    自上而下的软件开发和自下而上的软件开发
    没有发布过产品的程序员不知道什么是真正的软件
    20个数据库设计的最佳实践
    59条搞笑但却真实无比的编程语录
    自己动手跟着Jwt标准实现Jwt
    Gitlab-Runner基础教程
  • 原文地址:https://www.cnblogs.com/tianzhiliang/p/1932603.html
Copyright © 2011-2022 走看看