所謂獲取 WCF 服務元數據,本質上是獲取服務端點的詳細資訊 —— 即位址、繫結、契約 (ABC)。Juval Löwy 在《Programming WCF Services》一書中以棒棒糖圖示生動呈現端點構成。
WCF 服務可包含多個端點,每個端點都是通訊入口。掌握端點詳細資訊有助於深入剖析服務定義、內容與執行方式。
IMetadataExchange,使用 WS-MetadataExchange (MEX) 協定對應 MetadataExchangeClientMode 列舉:
public enum MetadataExchangeClientMode
{
MetadataExchange, // MEX 端點
HttpGet // HTTP-GET
}
定義於 System.ServiceModel.Description,包含三大核心屬性:
public abstract class MetadataImporter
{
public abstract Collection<ContractDescription> ImportAllContracts();
public abstract ServiceEndpointCollection ImportAllEndpoints();
// 其他方法略
}
關鍵方法 ImportAllEndpoints() 回傳 ServiceEndpointCollection,可透過 Find() 或 FindAll() 依契約類型或位址查詢。
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);
}
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);
}
string mexAddress = "https://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();
注意:HTTP-GET 模式下元數據位址尾碼必須為 ?wsdl。
string mexAddress = "https://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 || endpoints.Count == 0)
{
string httpGetAddress = mexAddress.EndsWith("?wsdl") ? mexAddress : mexAddress + "?wsdl";
metadata = mexClient.GetMetadata(new Uri(httpGetAddress), MetadataExchangeClientMode.HttpGet);
importer = new WsdlImporter(metadata);
endpoints = importer.ImportAllEndpoints();
}
foreach (ServiceEndpoint endpoint in endpoints)
{
Console.WriteLine("Endpoint Name: {0}", endpoint.Name);
Console.WriteLine("Address: {0}", endpoint.Address.Uri.AbsoluteUri);
Console.WriteLine("Binding: {0}", endpoint.Binding.GetType().ToString());
Console.WriteLine("Contract: {0}", endpoint.Contract.Name);
Console.WriteLine();
}
透過類似途徑,還可獲取服務契約、回呼契約、基底位址、繫結參數等更多元數據資訊,為服務治理、動態代理生成、自動化測試提供強力支援。