WCF獲取服務(wù)元數(shù)據(jù)經(jīng)驗(yàn)總結(jié)
WCF框架是目前比較受歡迎的一款由微軟研發(fā)的開發(fā)框架。它的出現(xiàn)實(shí)現(xiàn)了跨平臺的網(wǎng)絡(luò)解決方案。在這篇文章中就為大家介紹有關(guān)WCF獲取服務(wù)元數(shù)據(jù)的相關(guān)方法。#t#
所謂WCF獲取服務(wù)元數(shù)據(jù)(Metadata),歸根結(jié)點(diǎn),實(shí)際上就是獲取服務(wù)的終結(jié)點(diǎn)(Endpoint)的信息,這是服務(wù)公開在外的數(shù)據(jù)信息,包括Address、Binding與Contract,也就是所謂的ABCs。
WCF獲取服務(wù)元數(shù)據(jù)可能包含多個終結(jié)點(diǎn),每個終結(jié)點(diǎn)相當(dāng)于是通信的入口,客戶端和服務(wù)端通過終結(jié)點(diǎn)交換信息。
因而,如果能夠獲取終結(jié)點(diǎn)的詳細(xì)信息,有助于我們更好地剖析服務(wù)的定義、內(nèi)容與執(zhí)行方式。
服務(wù)有兩種方案可以發(fā)布自己的元數(shù)據(jù)。一種是基于HTTP-GET協(xié)議提供元數(shù)據(jù);另一種則為元數(shù)據(jù)交換方式,它往往使用一個專門的終結(jié)點(diǎn),稱之為元數(shù)據(jù)交換終結(jié)點(diǎn)。元數(shù)據(jù)交換終結(jié)點(diǎn)與其它終結(jié)點(diǎn)相似,仍然包含了地址、綁定與契約,但是使用的服務(wù)契約為WCF提供的接口IMetadataExchange。
實(shí)際上,這兩種發(fā)布元數(shù)據(jù)的方式代表了它使用了兩種不同的WCF獲取服務(wù)元數(shù)據(jù)標(biāo)準(zhǔn)協(xié)議,前者為HTTP/GET請求,后者為WS-MetadataExchange(MEX)。在WCF,以MetadataExchangeClientMode枚舉類型表示這兩種元數(shù)據(jù)交換模式:
- public enum Metadata
ExchangeClientMode- {
- MetadataExchange,
- HttpGet
- }
WCF為終結(jié)點(diǎn)定義了一個專門的ServiceEndpoint類,被定義在System.ServiceModel.Description命名空間中。ServiceEndpoint類包含了EndpointAddress,Binding,ContractDescription三個類型的屬性,分別對應(yīng)Endpoint的Address,Binding,Contract。
要WCF獲取服務(wù)元數(shù)據(jù)的終結(jié)點(diǎn),可以通過抽象類MetadataImporter獲取,類的定義如下:
- public abstract class
MetadataImporter- {
- public abstract Collection
<ContractDescription>
ImportAllContracts();- public abstract Service
EndpointCollection
ImportAllEndpoints();- //其它方法略;
- }
在類中,最重要的一個方法是ImportAllEndpoints(),它能夠獲取服務(wù)的所有終結(jié)點(diǎn),并返回一個ServiceEndpointCollection類型的對象。該類型為一個終結(jié)點(diǎn)集合,可以通過調(diào)用ServiceEndpointCollection的Find()方法或FindAll()方法,找到符合條件的一個或多個終結(jié)點(diǎn)。它的定義如下:
- public class ServiceEndpointCollection
: Collection<ServiceEndpoint>- {
- public ServiceEndpoint Find
(Type contractType);- public ServiceEndpoint Find(Uri address);
- public Collection<ServiceEndpoint>
FindAll(Type contractType);- //其它成員略
- }
我們可以通過契約類型,或者服務(wù)契約的地址,查找符合條件的終結(jié)點(diǎn)。
MetadataImporter類只是一個抽象類,如果要獲取WSDL元數(shù)據(jù),還會需要使用繼承它的子類型WsdlImporter:
- public class WsdlImporter :
MetadataImporter- {
- public WsdlImporter(MetadataSet
metadata);- public Collection<Binding>
ImportAllBindings();- public override Collection
<ContractDescription> ImportAllContracts();- public override ServiceEndpoint
Collection ImportAllEndpoints();- public ServiceEndpointCollection
ImportEndpoints(Binding wsdlBinding);- //其它成員略;
- }
如果要使用WsdlImporter,需要為其構(gòu)造函數(shù)傳遞一個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);- //其它方法略;
- }
假定服務(wù)公開的元數(shù)據(jù)地址為http://localhost:8001/IMyService?wsdl,則WCF獲取服務(wù)元數(shù)據(jù)的方法如下:
- 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模式,則元數(shù)據(jù)地址的后綴必須為?wsdl。由于我們在調(diào)用MetadataExchangeClient的GetMetadata()方法時,傳遞的MetadataExchangeClientMode枚舉參數(shù)值為HttpGet,因此獲取的為基于HTTP-GET的元數(shù)據(jù)。
如果服務(wù)使用的協(xié)議為HTTP或者HTTPS,則可能使用元數(shù)據(jù)交換終結(jié)點(diǎn),也可能為Http-Get模式。此時,我們可以先獲取元數(shù)據(jù)交換終結(jié)點(diǎn),如果沒有找到,再獲取基于HTTP-GET的終結(jié)點(diǎn):
- 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獲取終結(jié)點(diǎn)的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();
- }
通過以上介紹的類,采用相似的途徑,還可以實(shí)現(xiàn)更多的WCF獲取服務(wù)元數(shù)據(jù),例如服務(wù)契約、回調(diào)契約、基地址、地址、綁定等信息。