I recently wrote an article for DevelopMentor's Developments newsletter entitled
Building a Twitter Application in .NET.
You can read it at the DevelopMentor website:
http://www.develop.com/twitternetapps
I've republished here for my readers. Enjoy!
Building a Twitter Application in .NET
by Michael Kennedy (
@mkennedy)
http://www.michaelckennedy.net
Twitter has become one of the web's hottest properties. It is a central part of
mainstream news programs such as CNN's Anderson Cooper 360, congressional debates,
and talk shows. In fact, it grew at a rate of 1400% this past year [bit.ly/jG9BG].
If your company wants to interact with your customers in a modern and engaging experience,
you need to be on Twitter. In fact, if you have customers that really like or dislike
you, they are probably talking about you on Twitter. You should be part of that
conversation.
In this article, we will explore how to build a rich interactive experience on Twitter
that goes beyond just creating a new Twitter account. We will build a .NET application
that uses the Twitter API (a free service) alongside other cool technologies such
as the WCF REST Starter Kit [http://bit.ly/v8mBb]
and LINQ to fully leverage the Twitter experience.
Whether you want to build a community around your brand or you want to build the
next real-time, social community website like .NET Developer Buzz [http://dotnet.ubbuzz.com/], this article will cover the
technologies required to get the job done.
If you want to download the sample application to follow along, you can get it here:
http://www.michaelckennedy.com/Samples/SampleStatusUpdater.zip
While you're at it, be sure to follow DevelopMentor on Twitter:
http://twitter.com/dm_the_company
Let's Start Small
I will show you how to fully leverage the Twitter API, but many tasks can be accomplished
using simpler tools and you may be better starting there. Let's look at a few things
that we can do without the Twitter API.
Case 1. You want to display your latest Twitter messages on your website.
Your tweets[1], as they're called, can be consumed as a simple RSS feed. So you
may want to simply pull this feed into your website rather than digging into the
Twitter API and consuming custom XML or JSON formats. An example of consuming Twitter
in this fashion can be found on my website's front page [http://www.michaelckennedy.net/].
To get your RSS feed, just visit your profile page and get the RSS tweet link, e.g.
"RSS feed of mkennedy's tweets" [http://bit.ly/guhZU]
[1] Tweet - these are what the individual messages sent on Twitter are called. If the name sounds weird, I'm sure you'll get used to it. Remember that there was a time when Google was just a noun.
Case 2. You want to watch and manage multiple accounts at the same time.
Most Twitter clients only support a single user. But there are a couple of good
tools that allow you to manage multiple accounts. My current favorite is one called
bDule and you can get for free at
http://www.sobees.com/bdule.
Beyond the Small
There are times when you want to do more than simply syndicate your Twitter stream.
Let me give you an example. At DevelopMentor, we have had many instructors on Twitter
talking about their own interests. But we didn't have a corporate Twitter presence.
We decided to create our corporate presence by pulling all our instructors individual
tweets and rebroadcasting them from our DevelopMentor Twitter account:
@dm_the_company
We wanted to keep a sense of the original instructor who wrote the message, so we
append on an attribution. For example:
"Software Transactional Memory is released! (via @mkennedy)
and we wanted to do this in a flexible way. In short, we needed more functionality
than Twitter provides.
There are actually three services that do this sort of thing and they looked promising.
http://www.connecttweet.com/
http://www.grouptweet.com/
http://cotweet.com/
But in the end, nothing completely matched our requirements. So we decided to write
our own application to publish everyone's tweets under the DevelopMentor banner.
There are few simple steps involved as well as a lot of details we won't go into
yet.
- Take a list of Twitter accounts and download everyone's statuses.
- Determine which messages we haven't seen before.
- Publish these new statuses under our corporate account.
We can actually implement a simplistic version of this by continuing to use the
public RSS feeds of the individual accounts in conjunction with a very handy Twitter
API wrapper called TwitterooCore which you can find at http://rareedge.com/twitteroo/blog/.
The Twitter API
In practice, there is simply data missing from the RSS feed that we require as well
as features missing from the Twitteroo Core that move us deeper into the Twitter
API. One thing you may well miss is the ability to tie together conversations. For
example if Bob says "hello" and Jerry says in reply "@bob Back at you!" Twitter
tracks that Jerry replied to Bob and publishes this link in the stream. To get access
to these types of features and many other optimizations, you'll need to use the
REST-based Twitter API.
The Twitter API is documented at
http://apiwiki.Twitter.com/
There you can do things like get the users tweets, if their tweets are public, by
requesting:
http://twitter.com/statuses/user_timeline.xml?screen_name=mkennedy
What you get back to dependent on the requested format. Here we're asking for XML
(user_timeline.xml) but we can also get JSON, RSS, or ATOM.
Similarly, we can update our status by making a POST request to:
http://twitter.com/statuses/update.xml
Here again we have the four possible formats: XML, JSON, RSS, ATOM. However this
time we're using a form post for the request to update the user status which is
then in-turn returned as XML.
Great, we have this cool REST API based on loosely-typed GETs and POSTs. Should
we program against it using fundamental .NET types such as WebRequest, WebClient,
and similar classes? We could. But WebRequest is so
.NET 1.0 (circa 2001). There is a much newer API on the verge of release from Microsoft:
The REST Starter Kit [http://bit.ly/1IF3Ji].
While this toolkit is generally geared towards building to RESTful WCF services,
there's also a great set of classes for building REST clients. We will use these
classes to write our application. Let's take a look at how we can use the Twitter
API to write are simple application.
The REST Starter Kit
Part 1 - Getting the users of tweets.
We need to download the users messages as XML and convert them to .NET objects that
we can consume our application. This is really straightforward because the REST
Starter Kit as a cool feature to Visual Studio: "Paste XML as Types". This feature
will take an XML file and auto-generate types based on the inferred XML schema.
In our case, the XML file we will use is returned from the user timeline.
http://twitter.com/statuses/user_timeline.xml?screen_name=mkennedy
Open a link in a web browser, choose view source, and copy some XML. Then go to
Visual Studio, choose edit, Paste XML as Types. Of course you must have the REST
Starter Kit installed for this to work.[2]
[2] In my experience I ran into some errors deserializing the response from Twitter.
See the The Real World Intrudes section at the end of
the article if you run into difficulties.
After generating our status related types, we can use the HttpClient class to download
the statuses.
Listing 1.
private static void GetStatuses(IEnumerable userNames)
{
XmlSerializer serl = new XmlSerializer(typeof (statuses));
serl.UnknownElement += delegate { };
foreach (string name in userNames)
{
string url = string.Format(
"http://twitter.com/statuses/user_timeline.xml?screen_name={0}",
name);
HttpClient client = new HttpClient(url);
HttpResponseMessage response = client.Get();
response.EnsureStatusIsSuccessful();
string contents = response.Content.ReadAsString();
Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(contents));
statuses userStatuses = (statuses) serl.Deserialize(stream);
if ( userStatuses.status.Length > 0 )
{
Console.WriteLine( "@{0}'s latest tweet: {1}", name,userStatuses.status[0].text );
}
Console.WriteLine();
}
}
There are two main things happening in this code. We're using the HttpClient class
to download the web content associated with the given user's timeline. Then we're
using the XmlSerializer in conjunction with the auto-generated XML-serializable
types from the "Paste XML as Types" command. That's all there is to it. The REST
Starter Kit does most of the work for us.
Part 2 - Checking for New Messages
Now that we have all the statuses, we need to find the ones that we haven't broadcasted
from our main account and send them along to step 3. We won't go into detail on
how to track that. But you can imagine a simple database that facilitates a LINQ
to SQL query like this:
Listing 2.
public StatusUpdate[] FindRebroadcastableStatuses(StatusUpdate[] updates)
{
return
(from up in updates
let neverPosted = up.User.LastPostBroadcasted == null
let afterPostDate = up.Time > up.User.LastPostBroadcasted
where neverPosted || afterPostDate
select up).ToArray();
}
Part 3 - Publishing the Statuses
Now that we've gathered the statuses of our various users, it's time to rebroadcast
them to our community. We're going back to the Twitter API to update our status.
Again will use the HttpClient class and following the RESTful principle of using
POST to add new items to a given URI. We will do an HTTP POST to our status to add
a new message to the account.
Listing 3.
private void UpdateStatus(string newStatus, long? replyToId)
{
string url = "https://twitter.com/statuses/update.xml";
HttpClient client = new HttpClient( url );
client.TransportSettings.Credentials =
new NetworkCredential( twitterUser, password );
HttpUrlEncodedForm form = new HttpUrlEncodedForm();
form.Add( "status", newStatus );
if ( replyToId != null )
{
form.Add( "in_reply_to_status_id", replyToId.ToString() );
}
HttpContent content = form.CreateHttpContent();
HttpResponseMessage message = client.Post( "", content );
message.EnsureStatusIsSuccessful();
}
This time we create an HTML form using the HttpUrlEncodedForm class. We set the
status field to our new status. If this status as a response to a previous tweet
then we add the in_reply_to_status_id so Twitter knows to add a "in reply to..."
tag to the tweet.
And there you have it. Working with the Twitter REST API is really quite straightforward.
If you use the REST Starter Kit it's downright easy.
The Real World Intrudes
But wait a minute. This is reality and building bulletproof applications is never
that simple. There are at least five significant gotchas you have to address in
practice when working with Twitter and the REST Starter Kit.
1. There will be times when Twitter is unavailable. You have to be ready for crashes
and other types of randomness.
Twitter is one of those sites that can barely handle the traffic it is receiving.
With its 1400% growth, this isn't getting much better. So you must program defensively
and assume that many of your API requests will fail.
2. The Twitter API is a free service. By default, you are limited to a small number
of requests per hour. Many of the limits are around 150 API calls / hour. You may
need to carefully design your application to work within the limits. Some applications
simply need more data than this permits. For example, .NET Dev Buzz [http://dotnet.ubbuzz.com/] has to track thousands of users.
In that case, you will have to get your application white listed with Twitter. You
can do that here:
http://twitter.com/help/request_whitelisting
3. The date-time format used by the Twitter API is not directly parseable in .NET.
The format returned is in the format "Fri Feb 01 18:18:08 +0000 2008". But if we
change this to "Fri Feb 01 +0000 2008 18:18:08" it is parsable. So you might need
to adjust these date-time values.
4. You will get 417 error codes when you try to talk to Twitter using the default
configuration. The fix is not immediately apparent, but it is very simple. So if
you see the following error:
System.ArgumentOutOfRangeException: ExpectationFailed (417) is not one of the following:
OK (200), Created (201), Accepted (202), NonAuthoritativeInformation (203), NoContent
(204), ResetContent (205), PartialContent (206) at Microsoft.Http.HttpMessageExtensions.EnsuRESTatusIs()
Just to set the following property: ServicePointManager.Expect100Continue = false;
5. "Paste XML as Types" doesn't entirely work. For some reason, certain messages
from Twitter are not deserializable to the types generated with this command. My
experience was that I didn't actually care about the data causing the problem. So
I just removed that part of the generated type. You may have to subscribe to the
XmlSerializer error events to prevent exceptions.
Conclusions
I hope you now have a greater appreciation for what you can do with Twitter and how
it can help you build your brand or build engaging applications. We've used the
REST Starter Kit to make it easy to consume the Twitter API. You've even seen some
of the odd things that can go wrong and how to fix them. Don't forget to download
the sample application here:
http://www.michaelckennedy.com/Samples/SampleStatusUpdater.zip
Now get out there and build something cool.