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

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

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

服务有两种方案可以发布自己的元数据。一种是基于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,如下图:
 

要获取服务的终结点,可以通过抽象类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();
}

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

以上内容是转发学习记录过程。勿喷

WCF获取元数据的更多相关文章

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

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

  2. WCF分布式开发步步为赢(3)WCF服务元数据交换、配置及编程开发

    今天我们继续WCF分布式开发步步为赢(3)WCF服务元数据交换.配置及编程开发的学习.经过前面两节的学习,我们了解WCF分布式开发的相关的基本的概念和自定义宿主托管服务的完整的开发和配置过程.今天我们 ...

  3. WebService及WCF获取客户端IP,端口

    wcf获取客户端IP,端口 var context = OperationContext.Current; var properties = context.IncomingMessageProper ...

  4. MySQL:获取元数据

    元数据就是描述数据的数据,在很多时候我们都需要查询元数据 比如:想知道数据库有多少个表,表里面有哪些字段,数据表是什么时候创建的.在什么时候更新过等等 使用SQL注入的时候也得获取数据库的元数据才能进 ...

  5. 关于WCF测试时出现无法从***获取元数据问题

    在我们已经创建成功一个WCF服务后,通过本机localhost访问和测试均没有任何问题.但是寄宿在IIS/其他平台下时便会出现以下的错误信息 1.使用WCF Test Client错误 2.通过C#引 ...

  6. 【转】“无法从http://XXX/XXX.svc?wsdl获取元数据”错误的解决方法

    昨天在用IIS部署一个WCF服务时,碰到了如下错误: 理解了文档内容,但无法进行处理.  - WSDL 文档包含无法解析的链接.  - 下载“http://admin-pc/IISHostServic ...

  7. WCF获取客户端IP和端口

    //提供方法执行的上下文环境 OperationContext context = OperationContext.Current; //获取传进的消息属性 MessageProperties pr ...

  8. MySQL数据库(9)----从命令行获取元数据

    1. mysqlshow 命令提供的信息与某些 SHOW 语句很相似,因此可以从命令行提示符获取数据库和表的信息. (i)列出服务器所管理的数据库: root@javis:~$ mysqlshow - ...

  9. MySQL——获取元数据

    ---------------------------------------------------------------------------------------------------- ...

随机推荐

  1. 【linux高级程序设计】(第十五章)UDP网络编程应用 2

    UDP广播通信 单播:一对一,TCP和UDP均可完成 广播:只能UDP完成.广播时发送方只发送一个数据包,但是网络上的交换机默认转发广播数据包到所有端口.路由器默认不转发任何广播数据包.故广播在局域网 ...

  2. PhpStrom弹窗License activation 报 this license BIG3CLIK6F has been cancelled 错误的解决。

    将“0.0.0.0 account.jetbrains.com”添加到hosts文件中

  3. 陕西师范大学第七届程序设计竞赛网络同步赛D ZQ的睡前故事【约瑟夫环1-N数到第k个出队,输出出队顺序/ STL模拟】

    链接:https://www.nowcoder.com/acm/contest/121/D来源:牛客网 题目描述 ZQ是一个拥有n女朋友的万人迷,她的每一个女朋友每天晚上都会挨个给他打电话,要他讲了睡 ...

  4. POJ 3281 Dining(网络流拆点)

    [题目链接] http://poj.org/problem?id=3281 [题目大意] 给出一些食物,一些饮料,每头牛只喜欢一些种类的食物和饮料, 但是每头牛最多只能得到一种饮料和食物,问可以最多满 ...

  5. InputSplit—>RecordReder—>map(key,value,context)的过程解析

    上图首先描述了在TaskTracker端Task(MapTask.ReduceTask)的执行过程,MapTask(org.apache.hadoop.mapred)首先被TaskRunner调用,然 ...

  6. socket第三方库 AsyncSocket(GCDAsyncSocket)

    Socket描述了一个IP.端口对.它简化了程序员的操作,知道对方的IP以及PORT就可以给对方发送消息,再由服务器端来处理发送的这些消息.所以,Socket一定包含了通信的双发,即客户端(Clien ...

  7. 转:[Asp.net]常见数据导入Excel,Excel数据导入数据库解决方案,总有一款适合你!

    引言 项目中常用到将数据导入Excel,将Excel中的数据导入数据库的功能,曾经也查找过相关的内容,将曾经用过的方案总结一下. 方案一 NPOI NPOI 是 POI 项目的 .NET 版本.POI ...

  8. Xcode 5 单元测试(一)使用XCTest进行单元测试

    在Objc.io #1的Testing View Controllers中讲解的就是单元测试的相关内容.本文说下如何通过Xcode 5中集成的XCTest框架进行简单的单元测试. 什么是单元测试 首先 ...

  9. Android并发编程

    Android的并发编程,即多线程开发,而Android的多线程开发模型也是源于Java中的多线程模型.所以本篇也会先讲一些Java中的多线程理念,再讲解具体涉及的类,最后深入Android中的并发场 ...

  10. iOS:UICollectionView纯自定义的布局:瀑布流布局

    创建瀑布流有三种方式:   第一种方式:在一个ScrollView里面放入三个单元格高度一样的tableView,禁止tableView滚动,只需让tableView随着ScrollView滚动即可. ...