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.
Comments
Anonymous
April 21, 2008
PingBack from http://microsoftnews.askpcdoc.com/?p=3505Anonymous
April 24, 2008
Pedram, great posting. A quick question. Is there a way to consume a JSON based REST service? Thanks MarcAnonymous
May 02, 2008
This is good stuff . I was going to do this myself to see how this would work ..!!Anonymous
May 16, 2008
  I thought I would do some research on REST and I think this link  http://www.xfront.com/REST-Web-Services.htmlAnonymous
June 11, 2008
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!Anonymous
June 11, 2008
Can we invoke REST services asynchronously?Anonymous
July 09, 2008
very good,thank you for your shareAnonymous
July 09, 2008
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!Anonymous
September 18, 2008
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. ThanksAnonymous
October 13, 2008
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 .Anonymous
March 15, 2009
  This past Saturday was the Atlanta Code Camp.  I want to be make a point of thanking CliffAnonymous
March 18, 2009
Ingredients: Visual Studio 2008 SP1 (C#), WCF REST Starter Kit Preview 2 In Preview 1 of the WCF RESTAnonymous
August 12, 2009
great article, very helpful - thanks!Anonymous
October 29, 2009
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.Anonymous
February 02, 2010
That was so helpful that all you need to do now is add a printer friendly icon to your blog :DAnonymous
February 24, 2010
Is there a way to POST XML on the request directly instead of the URI way (i mean: URL?param1=value1¶m2=value2...) ?Anonymous
April 30, 2010
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);Anonymous
June 20, 2011
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!Anonymous
October 20, 2011
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());Anonymous
November 02, 2011
So there is no way to automatically generate client proxy if server has only webHttpBinding?Anonymous
November 04, 2011
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>Anonymous
February 14, 2012
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 confirmAnonymous
January 01, 2013
The comment has been removedAnonymous
May 21, 2013
It would be great if you can provide code file for it.Anonymous
September 03, 2013
Hi, Is there any way to consume the REST WCF in windows forms application ?Anonymous
January 06, 2014
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/.../62Anonymous
February 27, 2014
Nice ArticleAnonymous
September 23, 2014
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.