Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hide REST endpoint from MEX/WSDL in WCF

Tags:

rest

soap

wsdl

wcf

I have a WCF service that has REST and SOAP endpoints for every service. This was implemented similarly to this post: REST / SOAP endpoints for a WCF service with a configuration similar to the following:

<services>
  <service name="TestService">
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
    <endpoint address="soap" binding="basicHttpBinding" contract="ITestService"/>
    <endpoint address="rest" binding="webHttpBinding" contract="ITestService"/>
  </service>
</services>

The problem is that the REST endpoint shows up in the resulting WSDL as an additional port and binding.

Is there any way to prevent the REST endpoint from being included in the WSDL?

like image 614
WayneC Avatar asked Mar 02 '10 01:03

WayneC


3 Answers

You can get a copy of the WSDL, manually edit it to remove unwanted artifacts, and store it in a known location. Once you have the version of your WSDL that removes unwanted artifacts, you can redirect the ?wsdl query to that location:

<behaviors>
 <serviceBehaviors>
    <behavior name="TestServiceBehavior">
     <serviceMetadata httpGetEnabled="True" externalMetadataLocation="http://localhost/TestService.wsdl"/>
    </behavior>
 </serviceBehaviors>
</behaviors>

A couple caveats about this solution. You have to be careful about what you edit. If you change critical aspects of the contract, WCF may not be able to handle messages from clients generated from it. Removing an endpoint is generally not a big deal, however changing names for bindings, operations, message types, etc. can cause problems.

You also need to be aware of imports. The WSDL generated by WCF usually defines the endpoints, then imports another .wsdl that defines the actual service contract. The service contract wsdl in tern usually imports several .xsd files that define your message and data types. You will need to make sure you have copies of these uploaded relative to the root .wsdl, and that you update the import elements to reference them appropriately.

Another issue with this is that you are now manually controlling your contract...which means if you change it, you have to edit it again and replace it on whatever site you are hosting the .wsdl file. Now, a properly designed contract should NEVER change, as that breaks one of fundamental SOA rules about web services. However, it appears that you are doing code-first development, so its something to be aware of.

like image 194
jrista Avatar answered Oct 24 '22 01:10

jrista


It would be nice if there was an attribute to decorate the endpoint so that it is hidden from mex/wsdl generation in future versions of WCF for exactly this reason (hiding restful services from soap clients).

like image 1
infocyde Avatar answered Oct 24 '22 02:10

infocyde


Found a decent way to do this using an IWsdlExportExtension. There's probably a more robust/reusable way to do this, but this solution requires the convention of all REST endpoints to be named "REST". Below is the relevant part of an Endpoint behavior attached to all REST endpoints:

public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)
{
    // Remove all REST references (binding & port) from SOAP WSDL
    foreach (ServiceDescription wsdl in exporter.GeneratedWsdlDocuments)
    {
        // Remove REST bindings
        foreach (Binding binding in wsdl.Bindings)
        {
            if (binding.Name == "REST")
            {
                wsdl.Bindings.Remove(binding);
                break;
            }
        }

        // Remove REST ports
        foreach (Service service in wsdl.Services)
        {
            foreach (Port port in service.Ports)
            {
                if (port.Name == "REST")
                {
                    service.Ports.Remove(port);
                    break;
                }
            }
        }
    }  
}
like image 1
WayneC Avatar answered Oct 24 '22 01:10

WayneC