How to consume REST services with WCF

As you are probably aware by now, Windows Communication Foundation (WCF) 3.5 introduced a new binding called WebHttpBinding to create and to consume REST based services. If you are new to the WCF Web Programming model then see here for more details.

There have been many articles and blogs on how to host a RESTful service. However there doesn’t seem to be much written work on how to consume these services so I thought to write a few lines on this topic.

The new WebHttpBinding is used to configure endpoints that are exposed through HTTP requests instead of SOAP messages. So you can simply call into a service by using a URI. The URI usually includes segments that are converted into parameters for the service operation.

So the client of a service of this type requires 2 abilities: (1) Send an HTTP request, (2) Parse the response. The default response message format supported out of the box with the WebHttpBinding is “Plain old XML” (POX). It also supports JSON and raw binary data using the WebMessageEncodingBindingElement.

One way of consuming these services is by manually creating a HTTP request. The following example is consuming the ListInteresting operation from Flickr:

WebRequest request = WebRequest.Create("https://api.flickr.com/services/rest/?method=flickr.interestingness.getList&api_key=*&extras=");

WebResponse ws = request.GetResponse();

XmlSerializer s = new XmlSerializer(typeof(PhotoCollection));

PhotoCollection photos = (PhotoCollection)s.Deserialize(ws.GetResponseStream());

The idea is simple:

- Do the HTTP request and include all the parameters as part of the URI

- Get the response that is in XML format

- Either parse it or deserialize it into an object

The above code works but it is not elegant: We are not using the unified programming model offered by WCF and the URL is hacked together using string concatenation. The response is also manually deserialized into an object. With WCF and the WebHttpBinding we can automate most of this.

The first step is to define our service contract:

[ServiceContract]

[XmlSerializerFormat]

public interface IFlickrApi

{

  [OperationContract]

  [WebGet(

      BodyStyle = WebMessageBodyStyle.Bare,

      ResponseFormat = WebMessageFormat.Xml,

      UriTemplate = "?method=flickr.interestingness.getList&api_key={apiKey}&extras={extras}")]

  PhotoCollection ListInteresting(string apiKey, string extras);

}

As you can see, I am specifically instructing WCF to use the XML Serializer Formatter for this. The next step is to set the client endpoint. I decided to do this inside the config file:

<system.serviceModel>

  <client>

    <endpoint address="https://api.flickr.com/services/rest"

              binding="webHttpBinding"

              behaviorConfiguration="flickr"

              contract="FlickrApp.IFlickrApi"

              name="FlickrREST" />

  </client>

  <behaviors>

    <endpointBehaviors>

      <behavior name="flickr">

        <webHttp/>

      </behavior>

    </endpointBehaviors>

  </behaviors>

In order to be able to use the XML Serializer Formatter, I need XML Serializable types:

  [XmlRoot("photos")]

  public class PhotoCollection

  {

    [XmlAttribute("page")]

    public int Page { get; set; }

    ...

    [XmlElement("photo")]

    public Photo[] Photos { get; set; }

  }

  public class Photo

  {

    [XmlAttribute("id")]

    public string Id { get; set; }

    [XmlAttribute("title")]

    public string Title { get; set; }

    ...

  }

The final step is to create an instance of the client proxy:

ChannelFactory<IFlickrApi> factory =

  new ChannelFactory<IFlickrApi>("FlickrREST");

var proxy = factory.CreateChannel();

var response = proxy.ListInteresting("xxxx", "yyyy");

((IDisposable)proxy).Dispose();

If you don’t like using ChannelFactory directly then you can create your proxy by deriving from ClientBase<>:

public partial class FlickrClient :

  ClientBase<IFlickrApi>, IFlickrApi

{

  public FlickrClient()

  {

  }

  public FlickrClient(string endpointConfigurationName) :

    base(endpointConfigurationName)

  {

  }

  public FlickrClient(

    string endpointConfigurationName,

    string remoteAddress) :

    base(endpointConfigurationName, remoteAddress)

  {

  }

  public FlickrClient(string endpointConfigurationName,

    EndpointAddress remoteAddress) :

    base(endpointConfigurationName, remoteAddress)

  {

  }

  public FlickrClient(Binding binding,

    EndpointAddress remoteAddress) :

    base(binding, remoteAddress)

  {

  }

  public PhotoCollection ListInteresting(string apiKey, string extras)

  {

    return base.Channel.ListInteresting(extras);

  }

}

Now the client code will look similar to the following:

FlickrClient proxy = new FlickrClient();

var response = proxy.ListInteresting("xxxxxx","yyyyyy");

((IDisposable)proxy).Dispose();

Hope the above helps.