Social networking has reached critical mass. One unique social networking platform, Twitter, launched in March of 2006 and took the world by storm with its social networking and microblogging platform. The developers of Twitter had the forethought to provide a REST -based API. Numerous developers have used the REST-based API to build Twitter clients on dozens of different platforms. In this article I’ll demonstrate how to access Twitter using the .NET platform.

Twitter provides a unique communications platform. I like to think of it as a massively multi-player text messaging platform. The basic concept has three main actors: statuses (messages), followers (people who follow other people) and followees (people who are followed). Data basically flows like this: people post statuses, the statuses are persisted into the sender’s Twitter feed and replicated into their follower’s Twitter feeds.

Anatomy of a URL

The Twitter API provides a nicely structured and highly flexible set of mechanisms for accessing the Twitter platform. You access data from Twitter by calling specific URLS which Twitter processes and then Twitter returns your data in a number of standardized formats including XML, RSS, ATOM and JSON.

The Twitter URL API consists of three main parts: request, return type, optional parameters. Examine the following URL:

http://twitter.com/statuses/user_timeline/rodpaddock.xml

The first part of the message “/statuses/user_timeline” is the type of message (action) to process. The example message is used to return the timeline (last set of statuses) for a specified user.

The second part of the request is the basic parameter of the request. The sample parameter, “rodpaddock” is used by the “statuses/user_timeline” request to return my timeline.

The final parameter “.xml” specifies the data format I want Twitter to return to me. In this case, I’ve asked Twitter to return the data in XML format. Alternatively, to get another format back, I could change the extensions to one of these: .RSS, .JSON, or .ATOM.

Figure 1 demonstrates the data returned from the example call.

Figure 1:  XML returned from Twitter.
Figure 1: XML returned from Twitter.

Most Twitter REST calls also support a number of optional parameters. The user_timeline request has the following optional parameters:

  • id - returns messages using the posters id
  • count - returns specified number of messages (default is 20, maximum is 200)
  • since - returns messages since a specified date.
  • since-id - returns messages since a specified message id
  • page - returns messages from a specified display page

When passing optional parameters to Twitter you do it just like you would when passing parameters to a web call via the URL. The following call returns the last 200 messages from my timeline:

statuses/user_timeline/rodpaddock.xml?count=200

The following URL returns my last 200 statuses from December 1, 2008.

user_timeline/rodpaddock.xml?count=200&
since=Tue%2C+01+Dec+2008+22%3A55%3A48+GMT

Now I want to look at the data that Twitter returns. Twitter returns self-contained XML, meaning you don’t need to make follow up calls when dealing with XML return data. A status XML has this basic structure:

<statuses>
  <status>
    <created_at>
    <id>
    <text>
    <more elements….>
    <user>
      <id>
      <name>
      <screen_name>
      <profile_image_url>
      <more elements….>
    </use>
      </status>
</statuses>

As you can see, each status record contains all of its relevant data including the details of its creator. It doesn’t get much simpler than that.

The Simplest Thing that Could Possibly Work

Software guru Ward Cunningham described the concept of wikis (which he created) as the “simplest thing that could possibly work.” Talking to Twitter is just that simple…provided you have the proper tools.

The .NET Framework provides a great set of tools for accessing Twitter and you will be surprised just how simple it is. You use the .NET HttpWebRequest class partnered with a .NET StreamReader class. The following snippet shows how to send a call to Twitter and return its content to a string.

Function GetTweet(ByVal URL As String) _
   As String
   Dim Request As HttpWebRequest = _
       HttpWebRequest.Create(URL)
    Request.Method = "POST"

 Dim Response As WebResponse = Request.GetResponse
 Dim Reader As New _
  StreamReader(Response.GetResponseStream)
 
Dim Results As String = Reader.ReadToEnd
Reader.Close()
Response.Close()

Return Results
End Function

Now you have a simple function that accepts a URL and returns the results to a string. You can use this string just like you would use any string using the XML or JSON parser of your choice. The following code demonstrates querying the returned statuses using basic XPATH:

Dim TwitterLib As New TwitterLib
Dim URL As String =_
"http://.../statuses/user_timeline/rodpaddock.xml"
Dim XML As String = TwitterLib.GetTweet(URL)
Dim Doc As New XmlDocument
        Doc.LoadXml(XML)

Dim XMLNodes As XmlNodeList = _
  Doc.SelectNodes("//statuses/status/text")
For Each Node As XmlNode In XMLNodes
       Console.WriteLine(Node.InnerText)
Next

As you can see talking to Twitter is pretty simple. Now I’ll kick it up a notch.

Translating JSON

When dealing with REST-based Web services I prefer working with JSON (JavaScript Object Notation) objects because JSON is more object-like than XML is.

To use a JSON object in .NET you need to add a reference to the System.Web.Extensions namespace, which contains the JsonSerializer class. After importing this assembly you simply need to change the extension in your Twitter URL from .XML to .JSON. This will tell Twitter to return your results in JSON notation. Now change your code to implement the serializer as follows:

Dim TwitterLib As New TwitterLib
Dim URL As String = _
"http://../statuses/user_timeline/rodpaddock.json"

Dim Results As String = TwitterLib.GetTweet(URL)

Dim JsonSerializer As New_
System.Web.Script.Serialization._
JavaScriptSerializer

Dim ReturnObject As Object = 
JsonSerializer.DeserializeObject(Results)

For Each StatusObject As Object _
  In CType(ReturnObject, Array)
Console.WriteLine(StatusObject("text"))
    Console.WriteLine_ 
(StatusObject("user")("screen_name"))
Next

The code in the For loop shows how you can now access the data returned from Twitter in a more “object-like” manner. The first line of code references the elements on the status object itself. The second line of code shows how you access data from the user element of a status. Not too bad, eh?

Some Authorization Required

Some Twitter transactions require authentication. Posting status updates requires authentication against the Twitter API. This may sound challenging but it really isn’t. The Twitter API uses simple Web authentication which you can handle with the native .NET NetworkCredential class. Listing 1 shows the code necessary to send an authenticated request to update your status.

The update status code does a little more than just the simple request. Unique aspects of this code are:

  • It sets the Credentials property to the passed in Credentials object.
  • Uses the System.Web.HttpUtility class to URL encode content sent to Twitter.
  • Sets the content type and length to the proper encoding formats.
  • Sets the Expect100Continue property on the System.Net.ServicePointManager. If you don’t set this Twitter will return 417 response codes which will break your code. The reason for this is .NET’s default behavior of adding “100-Continue” headers to all its default requests.
  • Attaches the URL encoded parameters to the Web request using a stream writer.

Here you can see the code for calling the status update:

Dim URL As String = _
   "http://../statuses/update.json"

Dim Credentials As New _
  NetworkCredential("XXX", "XXX")

Dim DataToSend As String = "status=CoDe Mag Test"

Dim TwitterLib As New TwitterLib
 Dim res As String = _
TwitterLib.CallTweetAuthenticated(URL, 
Credentials, DataToSend)

MessageBox.Show(res)

Simple Client

Now I’ll create a simple client for displaying statuses to the screen. This application will consist of two parts. I’ll use a simple WPF-based ListBox to format status objects and a class to abstract away the complexities of the Twitter XML or JSON format.

Listing 2 is a domain object representing a status update. It has three properties: the message text, the poster’s screen name, and the URL to the poster’s image.

Listing 3 is the XAML for a formatted ListBox capable of showing the status updates pulled from the URL you looked at in the beginning of this article.

Finally, Listing 4 puts it all together. The code requests the timeline for “rodpaddock” in JSON format. The data is converted to a .NET array using the JSON serializer. The array is then transformed into a list of simple POCO (Plain Old CLR Objects) which are finally displayed in the sample WPF form.

You can see the final results of this in Figure 2.

Figure 2:  Simple Twitter WPF client.
Figure 2: Simple Twitter WPF client.

Twitter Complete

The Twitter API might look daunting at first but with a simple set of tools and techniques you can Twitter-enable your applications in a matter of minutes. And if you are looking for something to follow on Twitter, check out the following:

Listing 1: Code for sending an update to Twitter

Function CallTweetAuthenticated(ByVal URL As String, _
ByVal Credentials As NetworkCredential, _
ByVal Data As String) As String

Dim EncodedText As String = System.Web.HttpUtility.UrlEncode(Data)


'-- create request
Dim Request As HttpWebRequest = _
HttpWebRequest.Create(URL)

Request.Method = "POST"
Request.Credentials = Credentials
Request.ContentType = "application/x-www-form-urlencoded"
Request.ContentLength = EncodedText.Length
Request.UserAgent = "Rod Paddock CoDe Mag"
Request.Timeout = 10000


'-- set this parameter because Twitter will return 417 errors 
'-- 
without it
System.Net.ServicePointManager.Expect100Continue = False

'-- send parameters
Dim ReqStream As Stream = Request.GetRequestStream()
Dim Writer As New StreamWriter(ReqStream)
Writer.Write(EncodedText)
Writer.Close()

'-- call Twitter
Dim Response As WebResponse = Request.GetResponse
Dim Reader As New StreamReader(Response.GetResponseStream)
Dim Results As String = Reader.ReadToEnd

Reader.Close()
Response.Close()
Writer.Close()
ReqStream.Close()

Return Results

End Function

Listing 2: Simple Twitter Status domain class

Public Class Status
    Private _Text As String
    Public Property Text() As String
        Get
            Return _Text
        End Get
        Set(ByVal value As String)
            _Text = value
        End Set
    End Property

    Private _ScreenName As String
    Public Property ScreenName() As String
        Get
            Return _ScreenName
        End Get
        Set(ByVal value As String)
            _ScreenName = value
        End Set
    End Property

    Private _ImageURL As String
    Public Property ImageURL() As String
        Get
            Return _ImageURL
        End Get
        Set(ByVal value As String)
            _ImageURL = value
        End Set
    End Property
End Class

Listing 3: XAML code for displaying statuses

<ListBox IsSynchronizedWithCurrentItem="True" x:Name="lstResults" >
<ListBox.ItemTemplate>
 <DataTemplate>
  <StackPanel Orientation="Horizontal" >
   <Image Height="100" Width="100" 
     Source="{Binding Path=ImageURL}"/>
   <StackPanel>
        <TextBlock Text="{Binding Path=Text}"/>
        <TextBlock Text="{Binding Path=ScreenName}"/>
         <TextBlock Text="----------"/>
    </StackPanel>
   </StackPanel>
  </DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Listing 4: Querying and displaying Twitter data

Dim TwitterLib As New TwitterLib
Dim URL As String = _
         "http://.../statuses/user_timeline/rodpaddock.json"

Dim Results As String = TwitterLib.GetTweet(URL)
Dim JsonSerializer As New  _
       System.Web.Script.Serialization.JavaScriptSerializer
Dim ReturnObject As Object = _
       JsonSerializer.DeserializeObject(Results)
Dim StatusList As New List(Of Status)


For Each StatusObject As Object In CType(ReturnObject, Array)
  StatusList.Add(New Status With _
      { _
     .Text = StatusObject("text"), _
     .ScreenName =  StatusObject("user")("screen_name"), _
     .ImageURL = StatusObject("user")("profile_image_url") _
    })

Next

Me.lstResults.ItemsSource = StatusList