WCF: About Exposing Metadata 

Everything about WCF is about keeping your service boundary intact. By default this also applies to exposing/publishing metadata. In ASMX days, one would need to opt-out of exposing metadata, while in WCF, one has to opt-in.

Let's say, for example, you have the following service config declaration:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name = "Exposing.Metadata">
        <host>
          <baseAddresses>
            <add baseAddress =
                 "http://localhost:123/MetadataService
">
          </baseAddresses>
        </host>
        <endpoint address = ""
                  binding = "wsHttpBinding" 
                  contract = "Exposing.IServiceContract"/>
      </service>
    </services>
  </system.serviceModel>
</configuration>

This would host Exposing.Metadata service and define a single wsHttpBinding based endpoint listening at the base address.

So, the service endpoint address is http://localhost:123/MetadataService. If you would hit the endpoint URL with a web browser, a nice service page would be returned telling you that you have created a service, but there is no metadata exposed. So, hitting the endpoint with svcutil.exe would not allow you to grab metadata and generate the proxy code.

WCF, by default, does not expose any metadata. You have to ask for it nicely.

There are a couple of options to expose metadata of WCF services. The most basic way of doing it would be to expose it via HTTP based Get requests and retrieve WSDL. The following code fragment would do it, if you hosted the service using a ServiceHost class:

[ 1]  using (ServiceHost sh = new ServiceHost(typeof(OpService)))
[ 2]  {
[ 3]   ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
[ 4]   smb.HttpGetEnabled = true;
[ 5]   sh.Description.Behaviors.Add(smb);
[ 6]   sh.Open();
[ 7]   Console.WriteLine("Service running...");
[ 8]
[ 9]   Console.ReadLine();
[10]   sh.Close();
[11]  }
 
Lines 3-5 instantiate and add a service behavior that allows a simple HTTP Get request to succeed for metadata retrieval. Also, the mentioned service page would now render a link to the WSDL definition of the service.

Declarative configuration with the same effect is this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name = "MetadataBehavior">
         <serviceMetadata httpGetEnabled = "true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name = "Exposing.Metadata"
               behaviorConfiguration = "MetadataBehavior">
        <host>
          <baseAddresses>
            <add baseAddress =
                 "
http://localhost:123/MetadataService"/>
          </baseAddresses>
        </host>
        <endpoint address = "" 
                  binding = "wsHttpBinding"
                  contract = "Exposing.IServiceContract"/>
      </service>
    </services>
  </system.serviceModel>
</configuration>

We declared a behavior, called MetadataBehavior and assigned it to our Exposing.Metadata service.

There are a couple attributes in <serviceMetadata> element worth discussing:

  1. externalMetadataLocation allows you to specify the path to your WSDL metadata file, so you can provide it out of band and not rely on the infrastructure to generate it for you.
  2. httpGetEnabled exposes this metadata via HTTP transport.
  3. httpGetUrl enables you to define a different relative WSDL metadata endpoint address. If 'wsdl' was used, our service would expose WSDL metadata at http://localhost:123/MetadataService/wsdl.
  4. httpsGetEnabled allows you to expose metadata via HTTPS transport.
  5. httpsGetUrl is analog to httpGetUrl but for HTTPS.

This nails down all options one would want for exposing HTTP based metadata endpoints.

Now, exposing metadata using the WS-MetadataExchange (WS-MEX or MEX) protocol is also opt-in. First, you have an option to include only HTTP based metadata, as described. Second, there is a way to expose all metadata only using WS-MEX.

Here's how, first the config file:

<serviceBehaviors>
  <behavior name = "MetadataBehavior">
    <serviceMetadata />
  </behavior>
</serviceBehaviors>

Note: This is only the <serviceBehaviors> section, not the complete service config file.

You have to tell the hosting infrastructure to expose metadata by adding a service behavior with the <serviceMetadata> element. What this does, essentially, is add an interface called IMetadataExchange to your contract - but does not expose it yet. You have to add a metadata endpoint to your service and bind it to a transport of choice.

Continuing with previous service configuration, here's what we get:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name = "MetadataBehavior">
          <serviceMetadata/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name = "Exposing.Metadata"
               behaviorConfiguration = "MetadataBehavior">
        <host>
          <baseAddresses>
            <add baseAddress =
                 "
http://localhost:123/MetadataService"/>
          </baseAddresses>
        </host>
        <endpoint address = ""
                  binding = "wsHttpBinding"
                  contract = "Exposing.IServiceContract"/>
        <endpoint address = "mex"
                  binding = "mexHttpBinding"
                  contract = "IMetadataExchange"/>
      </service>
    </services>
  </system.serviceModel>
</configuration>

When this service is hosted, MEX metadata is exposed at http://localhost:123/MetadataService/mex and you can reach it with svcutil.exe or 'Add Service Reference' in Visual Studio. HTTP based WSDL access is not allowed since <serviceMetadata> element does not include the httpGetEnabled property with the value of true. It's false by default, which resonates nicely in terms of WCF's opt-in scenarios.

Remember, service orientation is about defining boundaries. And reaching metadata about your service should be confined to your choosing, not the platforms.

Categories:  .NET 3.0 - WCF
Monday, 19 February 2007 14:05:46 (Central Europe Standard Time, UTC+01:00)  #    Comments

 

Copyright © 2003-2024 , Matevž Gačnik
Recent Posts
RD / MVP
Feeds
RSS: Atom:
Archives
Categories
Blogroll
Legal

The opinions expressed herein are my own personal opinions and do not represent my company's view in any way.

My views often change.

This blog is just a collection of bytes.

Copyright © 2003-2024
Matevž Gačnik

Send mail to the author(s) E-mail