• 在WCF中获取服务元数据信息


    所谓获取WCF的服务元数据(Metadata),归根结点,实际上就是获取服务的终结点(Endpoint)的信息,这是服务公开在外的数据信息,包括Address、Binding与Contract,也就是所谓的ABCs。Juval Löwy在《Programming WCF Services》一书中,用生动形象的棒棒糖表示了终结点的构成:
     figure-1.5.gif

    WCF服务可能包含多个终结点,每个终结点相当于是通信的入口,客户端和服务端通过终结点交换信息,如下图所示:
     wcf07.gif

    因而,如果能够获取终结点的详细信息,有助于我们更好地剖析服务的定义、内容与执行方式。

    服务有两种方案可以发布自己的元数据。一种是基于HTTP-GET协议提供元数据;另一种则为元数据交换方式,它往往使用一个专门的终结点,称之为元数据交换终结点。元数据交换终结点与其它终结点相似,仍然包含了地址、绑定与契约,但是使用的服务契约为WCF提供的接口IMetadataExchange。

    实际上,这两种发布元数据的方式代表了它使用了两种不同的标准协议,前者为HTTP/GET请求,后者为WS-MetadataExchange(MEX)。在WCF,以MetadataExchangeClientMode枚举类型表示这两种元数据交换模式:
    public enum MetadataExchangeClientMode
    {
       MetadataExchange,
       HttpGet
    }

    WCF为终结点定义了一个专门的ServiceEndpoint类,被定义在System.ServiceModel.Description命名空间中。ServiceEndpoint类包含了EndpointAddress,Binding,ContractDescription三个类型的属性,分别对应Endpoint的Address,Binding,Contract,如下图:
     wcf08.gif

    要获取服务的终结点,可以通过抽象类MetadataImporter获取,类的定义如下:
        public abstract class MetadataImporter
        {
            public abstract Collection<ContractDescription> ImportAllContracts();
            public abstract ServiceEndpointCollection ImportAllEndpoints();
            //其它方法略;
    }

    在类中,最重要的一个方法是ImportAllEndpoints(),它能够获取服务的所有终结点,并返回一个ServiceEndpointCollection类型的对象。该类型为一个终结点集合,可以通过调用ServiceEndpointCollection的Find()方法或FindAll()方法,找到符合条件的一个或多个终结点。它的定义如下:
        public class ServiceEndpointCollection : Collection<ServiceEndpoint>
        {
            public ServiceEndpoint Find(Type contractType);
            public ServiceEndpoint Find(Uri address);

            public Collection<ServiceEndpoint> FindAll(Type contractType);
            //其它成员略
        }

    我们可以通过契约类型,或者服务契约的地址,查找符合条件的终结点。

    MetadataImporter类只是一个抽象类,如果要获取WSDL元数据,还会需要使用继承它的子类型WsdlImporter:
        public class WsdlImporter : MetadataImporter
        {
            public WsdlImporter(MetadataSet metadata);

            public Collection<Binding> ImportAllBindings();
            public override Collection<ContractDescription> ImportAllContracts();
            public override ServiceEndpointCollection ImportAllEndpoints();
            public ServiceEndpointCollection ImportEndpoints(Binding wsdlBinding);
            //其它成员略;
        }

    如果要使用WsdlImporter,需要为其构造函数传递一个MetadataSet类型的对象。而MetadataSet类型的对象则可以通过MetadataExchangeClient类的GetMetadata()方法获得。MetadataExchangeClient类的定义如下所示:
        public class MetadataExchangeClient
        {
            public MetadataExchangeClient();
            public MetadataExchangeClient(Binding mexBinding);
            public MetadataExchangeClient(EndpointAddress address);
            public MetadataExchangeClient(string endpointConfigurationName);
            public MetadataExchangeClient(Uri address, MetadataExchangeClientMode mode);

            public MetadataSet GetMetadata();
            public MetadataSet GetMetadata(EndpointAddress address);
            public MetadataSet GetMetadata(Uri address, MetadataExchangeClientMode mode);

            //其它方法略;
    }

    假定服务公开的元数据地址为http://localhost:8001/IMyService?wsdl,则获取服务元数据的方法如下:
    string mexAddress = “http://localhost:8001/IMyService?wsdl”;
    BasicHttpBinding binding = new BasicHttpBinding();
    MetadataExchangeClient mexClient = new MetadataExchangeClient(binding);
    MetadataSet metadata = mexClient.GetMetadata(new Uri(mexAddress), MetadataExchangeClientMode.HttpGet);
    MetadataImporter importer = new WsdlImporter(metadata);
    ServiceEndpointCollection endpoints = importer.ImportAllEndpoints();

    注意,如果是HttpGet模式,则元数据地址的后缀必须为?wsdl。由于我们在调用MetadataExchangeClient的GetMetadata()方法时,传递的MetadataExchangeClientMode枚举参数值为HttpGet,因此获取的为基于HTTP-GET的元数据。

    如果服务使用的协议为HTTP或者HTTPS,则可能使用元数据交换终结点,也可能为Http-Get模式。此时,我们可以先获取元数据交换终结点,如果没有找到,再获取基于HTTP-GET的终结点:
    string mexAddress = “http://localhost:8001/IMyService?wsdl”;
    BasicHttpBinding binding = new BasicHttpBinding();
    MetadataExchangeClient mexClient = new MetadataExchangeClient(binding);
    MetadataSet metadata = mexClient.GetMetadata(new EndpointAddress(mexAddress));
    MetadataImporter importer = new WsdlImporter(metadata);
    ServiceEndpointCollection endpoints = importer.ImportAllEndpoints();

    if (endpoints == null)
    {
    string httpGetAddress = mexAddress;
    if (!mexAddress.EndsWith(“?wsdl”) )
    {
        httpGetAddress += “?wsdl”;
    }
    BasicHttpBinding binding = new BasicHttpBinding();
    MetadataExchangeClient mexClient = new MetadataExchangeClient(binding);
    MetadataSet metadata = mexClient.GetMetadata(new Uri(mexAddress), MetadataExchangeClientMode.HttpGet);
    MetadataImporter importer = new WsdlImporter(metadata);
    endpoints = importer.ImportAllEndpoints();
    }

    在获得ServiceEndpointCollection集合对象后,就可以针对每个ServiceEndpoint获取终结点的Address、Binding、Contract的信息,如下所示:
    foreach (ServiceEndpoint endpoint in endpoints)
    {
    Console.WriteLine(“Endpoint Name is {0}”, endpoint.Name);
    Console.WriteLine(“Address is {0}”, endpoint.Address.Uri.AbsoluteUri);
    Console.WriteLine(“Binding is {0}”, endpoint.Binding.GetType().ToString());
    Console.WriteLine(“Address is {0}”, endpoint.Contract.Name);
    Console.WriteLine();
    }

    通过以上介绍的类,采用相似的途径,还可以获取更多元数据信息,例如服务契约、回调契约、基地址、地址、绑定等信息。

  • 相关阅读:
    HBase 使用与原理总结
    Java8 的一些使用总结
    对Redis的一些理解
    BERT模型源码解析 -- 转载
    BERT原理解析 -- 转载
    SQL 多表查询之 where和INNER JOIN
    Spark 数据处理相关代码
    Sql实战 1.单表复用进行比较排名
    LeetCode 47.括号生成 DFS递归
    LeetCode 46.机器人的运动范围
  • 原文地址:https://www.cnblogs.com/wayfarer/p/906075.html
Copyright © 2020-2023  润新知