Metadata and WCF Essentials
(Page 1 of 4 )
In this fourth article in a five-part series covering the Windows Communication Foundation, you'll learn about the metadata exchange endpoint, the metadata explorer, and more. It is excerpted from chapter one of the book
Programming WCF Services, written by Juval Lowy (O'Reilly, 2007; ISBN: 0596526997). Copyright © 2007 O'Reilly Media, Inc. All rights reserved. Used with permission from the publisher. Available from booksellers or direct from O'Reilly Media.
The Metadata Exchange Endpoint
The service can also publish its metadata over a special endpoint called the metadata exchange endpoint, sometimes referred to as the MEX endpoint. Figure 1-7 shows a service with business and a metadata exchange endpoint. However, you typically do not show the metadata exchange endpoint in your design diagrams.

Figure 1-7. The metadata exchange endpoint
That endpoint supports an industry standard for exchanging metadata, represented in WCF by theIMetadataExchangeinterface:
[ServiceContract(...)]
public interface IMetadataExchange
{
[OperationContract(...)]
Message Get(Message request);
//More members
}
The details of this interface are inconsequential. Like most of these industry standards, it is difficult to implement. Fortunately, WCF can have the service host automatically provide the implementation ofIMetadataExchangeand expose the metadata exchange endpoint. All you need to do is designate the address and the binding to use, as well as add the service metadata behavior. For the bindings, WCF provides dedicated binding transport elements for the HTTP, HTTPS, TCP, and IPC protocols. For the address, you can provide a full address or use any of the registered base addresses. There is no need to enable the HTTP-GET option, but there is no harm either. Example 1-12 shows a service that exposes three MEX endpoints, over HTTP, TCP, and IPC. For demonstration purposes, the TCP and IPC MEX endpoints use relative addresses and the HTTP one uses an absolute address.
Example 1-12. Adding MEX endpoints
<service name = "MyService" behaviorConfiguration = "MEX">
<host>
<baseAddresses>
<add baseAddress = "net.tcp://localhost:8001/"/>
<add baseAddress = "net.pipe://localhost/"/>
</baseAddresses>
</host>
<endpoint
address = "MEX"
binding = "mexTcpBinding"
contract = "IMetadataExchange"
/>
<endpoint
address = "MEX"
binding = "mexNamedPipeBinding"
contract = "IMetadataExchange"
/>
<endpoint
address = "http://localhost:8000/MEX"
binding = "mexHttpBinding"
contract = "IMetadataExchange"
/>
</service>
<behaviors>
<serviceBehaviors>
<behavior name = "MEX">
<serviceMetadata/>
</behavior>
</serviceBehaviors>
</behaviors>
Adding MEX endpoints programmatically
Like any other endpoint, you can only add a metadata exchange endpoint programmatically before opening the host. WCF does not offer a dedicated binding type for the metadata exchange endpoint. Instead, you need to construct a custom binding that uses the matching transport binding element, and then provide that binding element as a construction parameter to an instance of a custom binding. Finally, call the AddServiceEndpoint() method of the host providing it with the address, the custom binding, and the IMetadataExchange contract type. Example 1-13 shows the code required to add a MEX endpoint over TCP. Note that before adding the endpoint you must verify the presence of the metadata behavior.
Example 1-13. Adding TCP MEX endpoint programmatically
BindingElement bindingElement = new TcpTransportBindingElement();
CustomBinding binding = new CustomBinding(bindingElement);
Uri tcpBaseAddress = new Uri("net.tcp://localhost:9000/");
ServiceHost host = new ServiceHost(typeof(MyService),tcpBaseAddress);
ServiceMetadataBehavior metadataBehavior; metadataBehavior = host.Description.Behaviors.Find <ServiceMetadataBehavior>();
if(metadataBehavior == null)
{
metadataBehavior = new ServiceMetadataBehavior();
host.Description.Behaviors.Add(metadataBehavior);
}
host.AddServiceEndpoint(typeof(IMetadataExchange),binding,"MEX"); host.Open();
Streamlining with ServiceHost<T>
You can extend ServiceHost<T> to automate the code in Examples 1-11 and 1-13. ServiceHost<T> offers the EnableMetadataExchange Boolean property that you can call to both add the HTTP-GET metadata behavior and the MEX endpoints:
public class ServiceHost<T> : ServiceHost
{
public bool EnableMetadataExchange
{get;set;}
public bool HasMexEndpoint
{get;}
public void AddAllMexEndPoints();
//More members
}
When set to true,EnableMetadataExchangeadds the metadata exchange behavior, and if no MEX endpoint is available,EnableMetadataExchangeadds a MEX endpoint for each registered base address scheme. UsingServiceHost<T>, Examples 1-11 and 1-13 are reduced to:
ServiceHost<MyService> host = new ServiceHost<MyService>();
host.EnableMetadataExchange = true;
host.Open();
ServiceHost<T>also offers theHasMexEndpoint Boolean property, which returnstrueif the service has any MEX endpoint (regardless of transport protocol), and theAddAllMexEndPoints()method, which adds a MEX endpoint for each registered base address of the scheme type of HTTP, TCP, or IPC. Example 1-14 shows the implementation of these methods.
Example 1-14. Implementing EnableMetadataExchange and its supporting methods
public class ServiceHost<T> : ServiceHost
{
public bool EnableMetadataExchange
{
set
{
if(State == CommunicationState.Opened)
{
throw new InvalidOperationException("Host is already opened");
}
ServiceMetadataBehavior metadataBehavior;
metadataBehavior = Description.Behaviors.Find<ServiceMetadataBehavior>();
if(metadataBehavior == null)
{
metadataBehavior = new ServiceMetadataBehavior();
metadataBehavior.HttpGetEnabled = value;
Description.Behaviors.Add(metadataBehavior);
}
if(value == true)
{
if(HasMexEndpoint == false)
{
AddAllMexEndPoints();
}
}
}
get
{
ServiceMetadataBehavior metadataBehavior;
metadataBehavior = Description.Behaviors.Find<ServiceMetadataBehavior>();
if(metadataBehavior == null)
{
return false;
}
return metadataBehavior.HttpGetEnabled;
}
}
public bool HasMexEndpoint
{
get
{
Predicate<ServiceEndpoint> mexEndPoint= delegate(ServiceEndpoint endpoint)
{
return endpoint.Contract.ContractType == typeof(IMetadataExchange);
};
return Collection.Exists(Description.Endpoints,mexEndPoint);
}
}
public void AddAllMexEndPoints()
{
Debug.Assert(HasMexEndpoint == false);
foreach(Uri baseAddress in BaseAddresses)
{
BindingElement bindingElement = null;
switch(baseAddress.Scheme)
{
case "net.tcp":
{
bindingElement = new TcpTransportBindingElement();
break;
}
case "net.pipe":
{...}
case "http":
{...}
case "https":
{...}
}
if(bindingElement != null)
{
Binding binding = new CustomBinding(bindingElement);
AddServiceEndpoint(typeof(IMetadataExchange),binding,"MEX");
}
}
}
}
EnableMetadataExchangeverifies that the host has not been opened yet using theStateproperty of theCommunicationObjectbase class.EnableMetadataExchangedoes not override the configured value from the config file and will only set the value if no metadata behavior was found in the config file. When reading the value, the property checks if a value is configured. If no metadata behavior is configured at all,EnableMetadataExchangereturnsfalse, and if a behavior is configured, it simply returns itsHttpGetEnabledvalue. TheHasMexEndpointproperty uses an anonymous method* to initialize a predicate that checks if a given endpoint’s contract is indeedIMetadataExchange. The property then uses my staticCollection class and calls theExists()method, providing the collection of endpoints available with the service host.Exists()invokes the predicate on each item in the collection, and returnstrueif any one of the items in the collection satisfies the predicate (that is, if the invocation of the anonymous method returnedtrue), andfalseotherwise. TheAddAllMexEndPoints()method iterates over theBaseAddressescollection. For each
* If you are unfamiliar with anonymous methods, see my MSDN Magazinearticle “Create Elegant Code with Anonymous Methods, Iterators, and Partial Classes,” May 2004.
base address found, it creates a matching MEX transport-binding element, creates a custom binding, and uses that, as in Example 1-13 to add the endpoint.
Next: The Metadata Explorer >>
More Windows Scripting Articles
More By O'Reilly Media
|
This article is excerpted from chapter one of the book Programming WCF Services, written by Juval Lowy (O'Reilly, 2007; ISBN: 0596526997). Check it out today at your favorite bookstore. Buy this book now.
|
|