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(“http://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=http://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.

Comments (30)

  1. mhsimkin says:

    Pedram, great posting.  A quick question.  Is there a way to consume a JSON based REST service?

    Thanks

    Marc

  2. harishpa says:

    This is good stuff . I was going to do this myself to see how this would work ..!!

  3. John says:

    Hi Pedram!  Thanks for the info.  There’s a bug though – you have an endpointBehavior configured, but your endpoint is not referring to it.  You need to add ‘behaviorConfiguration="flickr"’ to the endpoint.  This is something I keep forgetting to do myself!

  4. Navin says:

    Can we invoke REST services asynchronously?

  5. jillzhang says:

    very good,thank you for your share

  6. jillzhang says:

    i have a problem

    when i call wcf method from extjs cross domain ,the response format can not adapt ,because it is either json or xml,neither is <script></script> format,it is perfect if wcf can response a cleartext format!

  7. John Fitzpatrick says:

    This was very helpful. I was using HttpWebRequest for REST and WCF for SOAP and of course it wasn’t unified. I hadn’t thought of doing it this way.

    Thanks

  8. Jose Manuel says:

    Hello! I’ve read you article lots of times, but I don’t understand any of those app.config settings. I really would like to use REST services from Community Server. I’ve got the documented REST API, but I need a little help. Please check it out:

    http://api.communityserver.org/

    I’m very interested in the blogs section. It uses headers for authentication.

    I can donate money if you help me. Thanks!

    I’ll follow your blog .

  9. &#160; This past Saturday was the Atlanta Code Camp.&#160; I want to be make a point of thanking Cliff

  10. Ingredients: Visual Studio 2008 SP1 (C#), WCF REST Starter Kit Preview 2 In Preview 1 of the WCF REST

  11. keith says:

    great article, very helpful – thanks!

  12. Jochen says:

    I find this example somehow funny: In the first few paragraphs you are showing a perfectly fine way to interact with an HTTP server and it only takes 4 lines of code.

    And then you are proposing something that takes tons of additional boilerplate code, requires lots of setup and is less flexible than just consuming the XML.

    That makes no sense to me whatsoever.

  13. Neil says:

    That was so helpful that all you need to do now is add a printer friendly icon to your blog 😀

  14. DotNetPuck says:

    Is there a way to POST XML on the request directly instead of the URI way (i mean: URL?param1=value1&param2=value2…) ?

  15. JJ says:

    how can I pass an array of objects in JSON to the service?

    I want to do somthing like this :

    I have the array of strings in JSON for example {"array":["one", "two"]}

    and make a POST request to the WCF service.

    For some kind of reason I do not understand the web method receives "array" parameter inside as null

    The WCF operation is defined:

    [OperationContract,

               WebInvoke(Method = "POST",

                               BodyStyle = WebMessageBodyStyle.WrappedResponse,

                               RequestFormat = WebMessageFormat.Json,

                               ResponseFormat = WebMessageFormat.Json)]

           string DoWork(string[] array);

  16. Mike says:

    Pedram,

    here's is my scenario:

    i've my WCF Rest service solution that has ICustomer contract.

    i want to use that RestService in my console app (client side).

    As per your explanation above,

    do i need to add ICustomer contract  (class) again on my console app?

    if not, do i need to add the Rest service dll?

    How my console app code recognize ICustomer if i create channelfactory?

    Please help!

  17. JH says:

    Hi,

    from the client side, how do you get the PhotoCollection type in the first place?

    If this was WCF, my service reference would resolve and proxy this class for me

    (and I'd be free to just go ahead and use it).

    how did you get the PhotoCollection object from the REST service before using it?

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

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

  18. So there is no way to automatically generate client proxy if server has only webHttpBinding?

  19. Tim says:

    Great post… While I'm creating my own implementation, I found it was helpful to see an example of the flickr response :  

    <photos page="2" pages="89" perpage="10" total="881">

    <photo id="2636" owner="47058503995@N01"

    secret="a123456" server="2" title="test_04"

    ispublic="1" isfriend="0" isfamily="0" />

    <photo id="2635" owner="47058503995@N01"

    secret="b123456" server="2" title="test_03"

    ispublic="0" isfriend="1" isfamily="1" />

    <photo id="2633" owner="47058503995@N01"

    secret="c123456" server="2" title="test_01"

    ispublic="1" isfriend="0" isfamily="0" />

    <photo id="2610" owner="12037949754@N01"

    secret="d123456" server="2" title="00_tall"

    ispublic="1" isfriend="0" isfamily="0" />

    </photos>

  20. gnanasekhar says:

    The above way of conusume is really a  restbased service..

    As the client call is not using Template URI of the rest service and using channelfactory , it is not a restbased service. please confirm

  21. Dhanvi says:

    Is there any settings need to do if my service provider has secure URL.

    I am getting following error;

    “The provided URI scheme 'https' is invalid; expected 'http'.”

  22. Prasad says:

    It would be great if you can provide code file for it.

  23. Hi,

    Is there any way to consume the REST WCF in windows forms application ?

  24. Jessica McNally says:

    Honestly, code wise, this is one of the best examples I've seen because you are, indeed, consuming an outside service and not trying to build it inside the app. That being said, what is missing from this example is several key screen shots on WHERE you are sticking your code inside the MVC api. This is not intuitive to beginners like me, and anyone familiar with the Visual Studio ASP.NET MVC environment knows there are multiple areas in the structure in which code is nested. This is why, as straightforward as your code seems, it is still not very helpful, and yet it really is one of the best examples I have found.

    Chewbacca!

    movie-sounds.net/…/62

  25. Sonu Thakur says:

    Nice Article

  26. Prashanth says:

    I agree with Jessica. There are several missing pieces to make this work. First of all how would the client application know that is the ServiceContract to be used in the Channel factory. I mean, since for the webHTTP binding SOAP header is not available.? Do i need to make direct reference? Even if so, after trying I dont see the channelfactory able to recognize my webhttp service hosted elsewhere. Request you to put screenshots of the all the pieces of code, if possible a sample app.