Creating a REST Client using WCF

Skill

Creating a REST Client using WCF

Posted in:

A couple of weeks ago we received an email about consuming a REST service in WCF. Well, this tutorial should answer that email. Today we're going to build a simple client for Twitter's REST API using WCF.

Since it doesn't look like WCF natively support OAuth authentication, the client we're going to write will do one simple thing - request the latest status updates for a specific user. I'm going to write a command line application that asks for a username and then prints a bunch of status updates along with information about the user. Below is some example output.

Name: Switch On The Code
Screen Name: switchonthecode
Date: Wed Sep 23 18:45:11 +0000 2009
Tweet: Introducing Google Chrome Frame (HTML5 and more in IE) http://sotc.me/94003 via Chromium Blog #ie #html5 #webstandards

Name: Switch On The Code
Screen Name: switchonthecode
Date: Tue Sep 22 18:36:38 +0000 2009
Tweet: iPhone game ported to Zune HD in just 12 hours http://sotc.me/73428 via @arstechnica #iphonedev #zunehd #monotouch

Name: Switch On The Code
Screen Name: switchonthecode
Date: Sat Sep 19 02:19:13 +0000 2009
Tweet: Our First Lua Tutorial - Simple Tables http://sotc.me/88709 #lua #tables
#gamescripting

There are lots of ways to setup a WCF client, and many times in the past I've done everything in code. Today, however, I'm going to setup the client using some configuration XML. The following XML should be added to your App.config file. If you don't have one, simply add one to your project.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <client>
      <endpoint address="http://twitter.com"
               binding="webHttpBinding"
               contract="TwitterWCF.ITwitter"
               behaviorConfiguration="twitter" />
    </client>
    <behaviors>
      <endpointBehaviors>
        <behavior name="twitter">
          <webHttp />
        </behavior>
      </endpointBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

This code will be used a little later by an object provided by WCF. Basically what we've created is an endpoint that uses http://twitter.com as its base URL, is configured to communicate over HTTP and will use the ITwitter interface that we haven't made yet.

As I just mentioned, communication will be done through the use of an interface - ITwitter. Let's look at that now.

using System.ServiceModel;
using System.ServiceModel.Web;

namespace TwitterWCF
{
  [ServiceContract]
  interface ITwitter
  {
    [OperationContract]
    [WebInvoke(
      UriTemplate="/statuses/user_timeline.xml?screen_name={username}",
      Method="GET")]
    Tweets GetTweets(string username);
  }
}

What we've created here is a ServiceContract with one exposed function - GetTweets. This functions takes the Twitter username you'd like to see the tweets for and returns a collection. The important part here is the WebInvokeAttribute. This attribute instructs WCF on how to request this information. The UriTemplate is straight from Twitter's API documentation and function parameters can be referenced by placing them in curly braces - {username}. WCF supports all types of HTTP communications needed for REST services. In this case, however, a simple GET is what's required.

The function we declared above returns a collection called Tweets. Let's take a look at this class now.

[CollectionDataContract(Name = "statuses", Namespace = "")]
public class Tweets : List<Tweet>
{

}

As you can see this is a very simple class that extends List. The Tweet object holds information about a single tweet, and we'll take a look at that in a minute. The important piece of information for this class is the CollectionDataContractAttribute. This tells WCF that this object is a collection and is defined in XML by the statuses tag. Since the Twitter API does not use namespaces in its XML, the Namespace property of this attribute is set to an empty string.

Basically, what we're doing is mapping what's returned in the Twitter API's XML to our custom set of objects. The next object holds an actual status update, Tweet.

[DataContract(Name="status", Namespace="")]
public class Tweet
{
  [DataMember(Name="id")]
  public string Id { get; set; }

  [DataMember(Name="text")]
  public string Text { get; set; }

  [DataMember(Name="created_at")]
  public string Date { get; set; }

  [DataMember(Name="user")]
  public User User { get; set; }
}

There are lots of fields available in a Twitter status update. Fortunately, you're not required to specify all of them. Above are the ones I'd like to display and each one has a DataMemberAttribute that tells WCF what XML tag represents the data.

There's one last object we need to look at - User. This object holds information about the user that created the status update. Every Tweet object has a reference to a User object.

[DataContract(Name="user", Namespace="")]
public class User
{
  [DataMember(Name="name")]
  public string Name { get; set; }

  [DataMember(Name="screen_name")]
  public string ScreenName { get; set; }
}

This object works just like the Tweet object. Simply create the properties you're interested in and use the DataMember attribute to tell WCF what XML tag the data is stored in.

That's it for creating our objects. If all the attributes are correctly specified, WCF will take care of deserializing the XML and populating the objects automatically. The last thing we need to do is create a client that will actually do the communication. We do this by sub-classing the ClientBase class.

class TwitterClient : ClientBase<ITwitter>, ITwitter
{
  public Tweets GetTweets(string username)
  {
    return this.Channel.GetTweets(username);
  }
}

When the ClientBase is created it will pull its configuration from the App.config file we specified at the beginning of this tutorial. We also make this class implement ITwitter, so we can wrap each function with a corresponding call to ClientBase's underlying Channel.

Lastly, we need to see how this object is actually used. Here's the code from my Main function that prints status updates to the console.

static void Main(string[] args)
{
  TwitterClient client = new TwitterClient();

  while (true)
  {
    Console.WriteLine("Username?");
    string input = Console.ReadLine();

    if (input == "exit")
      break;

    Tweets tweets = client.GetTweets(input);

    foreach (Tweet tweet in tweets)
    {
      Console.WriteLine("Name: " + tweet.User.Name);
      Console.WriteLine("Screen Name: " + tweet.User.ScreenName);
      Console.WriteLine("Date: " + tweet.Date);
      Console.WriteLine("Tweet: " + tweet.Text);
      Console.WriteLine();
    }
  }
}

The console application sits in a loop and asks for Twitter usernames. When a username is entered, it then loops through all the Tweets and prints information about the user and the contents of the status update. This code does not check for invalid input - so if you enter a username that doesn't exist, the program will crash.

And that's it. After creating several REST clients with different technologies, it's hard to beat WCF for ease and speed of development. You barely need to know anything about XML to create a working client. You can download the full source for the program above, and questions or comments are always welcome.

Sanket
10/03/2009 - 06:41

Very informative article and extremely timely as well since I was thinking of creating a Twitter app in the next few days :-).

Thanks a lot for sharing this.

reply

Add Comment

Put code snippets inside language tags:
[language] [/language]

Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]

See here for supported languages.

Javascript must be enabled to submit anonymous comments - or you can login.

Sponsors