Exposing WCF services with SOAP and REST endpoints

Simultaneously exposing a WCF service with both SOAP and REST endpoints is not as difficult as it may sound. It requires just a few updates to the codebase and configuration. But first, let’s start from the beginning.

This post assumes that you have a WCF service (new or existing) that is only providing a SOAP endpoint. I’m making this assumption because that is the default endpoint for any new WCF service that you create from Visual Studio. The goal is to reconfigure the service to expose the additional REST endpoint.

Another thing to consider is that how you call a service is not always the same thing as to what (format) you expect from it. In other words, if you are downloading a resource from a RESTful URL, then the resource being returned can still be any format such as XML or JSON (further assuming that that we’re talking about character data). However, nowadays, many RESTful services do in fact return JSON data as the default format, so we’ll make assumption in this post as well: that the REST endpoint will return JSON payload, while the SOAP endpoint returns an XML payload.

Let’s get to it.

First, we need to configure the REST endpoint:

  1. Open your WCF project/solution with Visual Studio.
  2. Open the application configuration file (app.config or web.config).
  3. Locate the appropriate service element (under configuration/system.ServiceModel/services).
    Note that the existence of an endpoint element which describes the SOAP endpoint.
  4. Add a new endpoint element under the service element that is similar to the SOAP endpoint; a simple copy/paste of the existing endpoint element should suffice.
  5. Ensure that address attribute for both endpoints are not the same because those values map to a part of the URL that exposes those endpoints.
    For example, provide “soap” and “rest” as values for the address attribute.
  6. Ensure that the newly created REST endpoint has a binding attribute value of webHttpBinding.
    Note that if you copied and pasted this element from the existing one that the binding attribute value will be basicHttpBinding (or some other type of binding).Your endpoint configuration should look similar to:

    <system.serviceModel>
    <services>
    <service name="SoapRestEnabledService.Service1">
    <host>
    <baseAddresses>
    <add baseAddress="http://localhost:8733/Design_Time_Addresses/SoapRestEnabledService/Service1/" />
    </baseAddresses>
    </host>
    <!-- Service Endpoints -->
    <!-- Unless fully qualified, address is relative to base address supplied above -->
    <endpoint address="soap" binding="basicHttpBinding" contract="SoapRestEnabledService.IService1">
    <identity>
    <dns value="localhost" />
    </identity>
    </endpoint>
    <endpoint address="rest" binding="webHttpBinding" contract="SoapRestEnabledService.IService1" behaviorConfiguration="restEndpointBehavior">
    <identity>
    <dns value="localhost" />
    </identity>
    </endpoint>
    <!-- Metadata Endpoints -->
    <!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
    <!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
    </service>
    </services>
    

Because we are assuming that the payload format for the REST endpoint should be JSON, we need to configure the endpoint to do so. To do this, we add an endpoint behavior.

  1. In the configuration file, locate the endpointBehaviors element (under configuration/system.serviceModel/behaviors).
  2. Add a new behavior element, and provide a name attribute value such as “restEndpointBehavior”.
  3. Add a new webHttp element in the new behavior.
    From here, we can either indicate that the payload is formatted automatically or specifically.
    To format it automatically, ensure that the automaticFormatSelectionEnabled is set to True.
    To format it specifically (to JSON), ensure that the defaultOutgoingResponseFormat is set to Json.Your new endpoint should look similar to:

    <endpointBehaviors>
      <behavior name="restBehavior">
        <webHttp helpEnabled="true" defaultOutgoingResponseFormat="Json" />
      </behavior>
    </endpointBehaviors>
    
  4. Now, associate the endpoint behavior to the endpoint itself by adding/modifying the behaviorConfiguration attribute on the endpoint (see the first xml configuration above).

The service is now configure to expose the service as both SOAP and REST endpoints.

But wait, we’re not done. We also have to enable the service methods for REST:

  1. Add a Reference to System.ServiceModel.Web to the project.
  2. Add WebGet or WebInvoke attributes to each method for the service. In some cases, such as using WebInvoke, you will need to use UriTemplates to better control the URL.Your service (interface) should now look similar to:
    [ServiceContract]
    public interface IService1
    {
        [WebGet]
        [OperationContract]
        string GetName();
    
        [WebInvoke(UriTemplate = "getdata/{value}")]
        [OperationContract]
        string GetData(string value);
    
        [WebInvoke]
        [OperationContract]
        CompositeType GetDataUsingDataContract(CompositeType composite);
    }
    

Well, that’s about the brunt of what needs to be changed.