所谓获取WCF的服务元数据(Metadata),归根结点,实际上就是获取服务的终结点(Endpoint)的信息,这是服务公开在外的数据信息,包括Address、Binding与Contract,也就是所谓的ABCs。Juval Löwy在《Programming WCF Services》一书中,用生动形象的棒棒糖表示了终结点的构成:
ide
WCF服务可能包含多个终结点,每一个终结点至关因而通讯的入口,客户端和服务端经过终结点交换信息,以下图所示:
函数
于是,若是可以获取终结点的详细信息,有助于咱们更好地剖析服务的定义、内容与执行方式。学习
服务有两种方案能够发布本身的元数据。一种是基于HTTP-GET协议提供元数据;另外一种则为元数据交换方式,它每每使用一个专门的终结点,称之为元数据交换终结点。元数据交换终结点与其它终结点类似,仍然包含了地址、绑定与契约,可是使用的服务契约为WCF提供的接口IMetadataExchange。对象
实际上,这两种发布元数据的方式表明了它使用了两种不一样的标准协议,前者为HTTP/GET请求,后者为WS-MetadataExchange(MEX)。在WCF,以MetadataExchangeClientMode枚举类型表示这两种元数据交换模式:
public enum MetadataExchangeClientMode
{
MetadataExchange,
HttpGet
}blog
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);ip
public Collection<ServiceEndpoint> FindAll(Type contractType);
//其它成员略
}string
咱们能够经过契约类型,或者服务契约的地址,查找符合条件的终结点。it
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();
}
经过以上介绍的类,采用类似的途径,还能够获取更多元数据信息,例如服务契约、回调契约、基地址、地址、绑定等信息。
以上内容是转发学习记录过程。勿喷