Whether you are living in COM, .NET, web services or any other distributed application technology it is clearly incredibly useful if you have a definitive statement of the contract that the service supports. Without it, writing clients can be a hit or miss exercise.

When using COM+ integration with Indigo to generate your services, it is simple to enable both common metadata patterns: MEX (WS-MetadataExchange) and HTTP GET access (the old and cruddy ?WSDL convention). For WinFX Beta 1 there is a little trick to making this useful which is why I’m posting...

Note that by default, the infrastructure will NOT enable metadata – the metadata exposure is a great development aid but in many cases it has little place in a production service. Advertising your access points could be a fine example of a denial-of-service waiting to happen.

So as in previous posts I’ll describe how metadata can be enabled (and made useful) with the help of a modification to the code from the “Integrating with a COM+ Application as an Indigo Service” sample from the WinFX SDK – install the SDK for the full sample solution.

  1. Build the solution to produce the esCalculator.dll Enterprise Services / COM+ component
  2. Enter gacutil.exe /i esCalculator.dll to add the assembly to the Global Assembly Cache
  3. Enter regsvcs.exe esCalculator.dll to register the assembly's component and the ServiceModelSample application with COM+
  4. Set the ServiceModelSample app to be a “Server application” rather than a “Library application”
  5. Set the ServiceModelSample app to “Leave running when idle”
  6. Enter ComSvcConfig.exe add /application:ServiceModelSample
    /interface:ServiceModelSample.esCalculator,ICalculator
    /hosting:complus /mex
    to expose the interface as a COM+ hosted service.

Note that step 6. specifies that we will use COM+ hosting mode and includes the optional /mex parameter – this will spit out the following config file in the standard location for COM+ app specific configuration (typically C:\Program Files\ComPlus Applications\{e146e066-d3d1-4e0e-b175-30160bd368de}\application.config for this example):

<?xml version="1.0" encoding="utf-8"?>

<configuration>

  <system.serviceModel>

    <behaviors>

      <behavior configurationName="ComServiceMexBehavior">

        <metadataPublishing enableGetWsdl="true" enableHelpPage="true"

          enableMetadataExchange="true" />

      </behavior>

    </behaviors>

    <services>

      <service behaviorConfiguration="ComServiceMexBehavior" serviceType="{BE62FF5B-8B53-476B-A385-0F66043049F6}">

        <endpoint address="net.pipe://localhost/E146E066-D3D1-4E0E-B175-30160BD368DE/BE62FF5B-8B53-476B-A385-0F66043049F6/mex"

          bindingConfiguration="comMexBinding" bindingSectionName="netProfileNamedPipeBinding"

          contractType="System.ServiceModel.IMetadataExchange, System.ServiceModel, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

        <endpoint address="net.pipe://localhost/E146E066-D3D1-4E0E-B175-30160BD368DE/BE62FF5B-8B53-476B-A385-0F66043049F6/C551FBA9-E3AA-4272-8C2A-84BD8D290AC7"

          bindingConfiguration="comNonTransactionalBinding" bindingSectionName="netProfileNamedPipeBinding"

          contractType="{C551FBA9-E3AA-4272-8C2A-84BD8D290AC7}" />

      </service>

    </services>

    <bindings>

      <netProfileNamedPipeBinding>

        <binding configurationName="comNonTransactionalBinding" />

        <binding configurationName="comTransactionalBinding" flowTransactions="Allowed" />

        <binding configurationName="comMexBinding" />

      </netProfileNamedPipeBinding>

    </bindings>

  </system.serviceModel>

</configuration>

The things to note from this configuration is that we we have two endpoints (one for the service and one for the metadata) and a metadataPublishing behavior. This behavior is a standard capability that can be enabled for Indigo services. Clearly you can tweak the metadataPublishing attributes if you love the ?WSDL and don’t like MEX or helping folks who send a browser to the metadata endpoint.

You will also notice that we default to both endpoints using the net.pipe transport. Again, for security reasons, if you want to start offering your COM+ apps over the network this is something that you are required to opt in to by editing the standard configuration.

Now for the Beta 1 downside…

In WinFX Beta 1 (Indigo Beta 1), the Service Model Metadata Utility Tool (SvcUtil.exe) only works with metadata over HTTP and not over named pipes. This is the command-line tool for building proxies so, as it stands, you will struggle (a bit) to use the default metadata from COM+ integration to help build your clients.

In time SvcUtil should work over other transports (there is nothing in WS-MetadataExchange that ties it to HTTP), but until then you probably want to edit your config so that your metadata is published over HTTP. The config file below shows how this is achieved:

<?xml version="1.0" encoding="utf-8"?>

<configuration>

  <system.serviceModel>

    <behaviors>

      <behavior configurationName="ComServiceMexBehavior">

        <metadataPublishing enableGetWsdl="true" enableHelpPage="true"

          enableMetadataExchange="true" />

      </behavior>

    </behaviors>

    <services>

      <service behaviorConfiguration="ComServiceMexBehavior" serviceType="{BE62FF5B-8B53-476B-A385-0F66043049F6}">

        <endpoint address="http://localhost:8099/E146E066-D3D1-4E0E-B175-30160BD368DE/BE62FF5B-8B53-476B-A385-0F66043049F6/mex"

          bindingConfiguration="comMexBinding" bindingSectionName="customBinding"

          contractType="System.ServiceModel.IMetadataExchange, System.ServiceModel, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

        <endpoint address="net.pipe://localhost/E146E066-D3D1-4E0E-B175-30160BD368DE/BE62FF5B-8B53-476B-A385-0F66043049F6/C551FBA9-E3AA-4272-8C2A-84BD8D290AC7"

          bindingConfiguration="comNonTransactionalBinding" bindingSectionName="netProfileNamedPipeBinding"

          contractType="{C551FBA9-E3AA-4272-8C2A-84BD8D290AC7}" />

      </service>

    </services>

    <bindings>

      <customBinding>
        <binding configurationName="comMexBinding">
          <httpTransport mapAddressingHeadersToHttpHeaders="false" />
        </binding>
      </customBinding>
      <netProfileNamedPipeBinding>

        <binding configurationName="comNonTransactionalBinding" />

        <binding configurationName="comTransactionalBinding" flowTransactions="Allowed" />

        <binding configurationName="comMexBinding" />

      </netProfileNamedPipeBinding>

    </bindings>

  </system.serviceModel>

</configuration>

The bold sections in green (for those of you reading in color) show how to modify the metadata address and binding to the HTTP transport.

Now you can:

  • send a browser to http://localhost:8099/E146E066-D3D1-4E0E-B175-30160BD368DE/BE62FF5B-8B53-476B-A385-0F66043049F6/mex to get a service help page
  • send a browser to http://localhost:8099/E146E066-D3D1-4E0E-B175-30160BD368DE/BE62FF5B-8B53-476B-A385-0F66043049F6/mex?wsdl to HTTP GET the WSDL
  • point SvcUtil to http://localhost:8099/E146E066-D3D1-4E0E-B175-30160BD368DE/BE62FF5B-8B53-476B-A385-0F66043049F6/mex to build a client proxy

I did intentionally avoid using port 80 for HTTP. This allows Indigo to start using the port 8099 address without worrying about a collision with IIS down on port 80 (the potential collision issue is specific to Windows XP).

Note also that in common with much of the rest of Indigo, this additional metadata behavior is all enabled and modified through configuration editing. No need to recode, recompile or redeploy.