Twitterlight: A Silverlight Twitter client
 | Twitter, using simple SMS length messages, has changed how people stay connected. Here's how to build a Silverlight web client to access the Twitter API and display your tweets in a layout of your choosing. The Twitterlight code provides a solid starting point for communicating with any RESTful service interface, and you'll also see how to overcome Silverlight's cross-domain call limitations by leveraging a local proxy web service. |
| Steve Holstad Difficulty: Intermediate Time Required: Greater than 10 hours Cost: Free Hardware: |

Developer Update (5/18/2009)
The Silverlight 2.0 RTW Source Code is available at the link below. Please note that the RTW version contains no reference to the Sapphire controls used during the SL 2 Beta.
Twitterlight_v22.zip
I am planning to create a new Twitterlight version for Silverlight 3, so I'm sad to say this code base won't be updated past 2.0. Thanks for the feedback and support!
Developer Update (4/1/2008)
Twitterlight has been updated to the newest Silverlight release: Silverlight 2.0 Beta 1. You'll need this runtime installed in order to run the app at twitterlight.com. Don't forget that to compile the code, you must download, install and add references to the appropriate ComponentOne Sapphire control set.
Introduction
I've become a big believer in the power of Twitter to keep an informal social network of like-minded folks loosely yet immediately connected. Often times developers have a decent number of contacts they'd like to keep in contact with, but perhaps don't always have time to reach out one-on-one often enough. Twitter provides a mechanism which somehow gives that constantly connected "feel". As a consultant that works at many sites, I wanted to create a web-based client to allow Twitterers like me to remain connected without the need for installing any applications on their current machine. Silverlight will give the UI more pop than the existing Twitter site, and provide features like auto-update and TinyURL support.
Notes
If you have a Twitter account, try the app at Twitterlight.com.
The Twitterlight project is written using the Silverlight 2.0 Beta 1. Previously this article was published using the Silverlight 1.1 Alpha September Refresh.
The Twitterlight project consists of a Silverlight application (TwitterSL), a web site (TwitterSLServer) and a class library containing common controls (TwitterSL.Common).
By now Silverlight is now infamous for its security setting which prevents cross-domain calls. What this means is that in order to serve external data, a Silverlight application must call to a web service hosted within the same domain. This proxy web service can then issue the post to the external data source (here the Twitter API), parse the result, and return back the result to the initial Silverlight code. Therefore the TwitterSLServer web site contains a local web service (TwitterWebService.asmx) to marshall the Twitter web requests, acting as a the proxy between Silverlight code and the Twitter API.
How it all works
Silverlight application (TwitterSL): The Silverlight project lives and dies with the Page.xaml markup and Page.xaml.cs code-behind. This code creates the application shell, collects user authentication info, and provides the mechanism for posting new statuses to Twitter (including TinyURL support). TinyURL, btw, is a must-have for Twitter, because posts are limited to the length of SMS messages, ~140 characters. TinyURL replaces a full-sized link with a mini-me version of the link, giving you extra room to vent about Roger Clemens or Kanye West's Grammy speech. Sweet.
The Page.xaml.cs code maintains a reference to the local web service and issues all Twitter API web requests asynchronously to this proxy. When a response is returned, the XML snippet is parsed and mapped to a new instance of TwitControl, and inserted into the message container. The app allows users to toggle the type of response returned, from Public (all latest posts), Archive (your posts), Replies (directed at you), and the standard Friends (you and all your buddies).
Control Toolset (ComponentOne Sapphire): I used ComponentOne's new Sapphire control toolset for this project. These controls add some nice functionality to a Silverlight project without forcing developers to create everything from scratch. I used C1's Label, LinkLabel and StackPanel to create the TwitControl, and the StackPanel and FlowPanel within Page.xaml to setup the layout of the application. I recommend trying these controls if you're starting out in Silverlight: a trial version is provided, and the support response was solid when I ran into a few minor issues. I'm excited to see the improvements to both Silverlight and the available control toolsets as they evolve together. One thing to note is that I created all third-party controls at runtime in order to avoid some VS designer issues, which should be corrected in the future.
You'll need to download and install this toolset from the ComponentOne site, and add references to C1.Silverlight.dll in order to compile the project.
Here's how to add a few controls to the XAML (the sp.ReplacePlaceHolder call swaps out a Silverlight placeholder with the newly created StackPanel):
C#:
/// <summary>
/// Builds third party controls dynamically at runtime
/// </summary>
private void CreateComponentOneControls()
{
TextBlock twitMessage = new TextBlock();
twitMessage.Width = 290;
twitMessage.FontSize = 11;
twitMessage.Foreground = new SolidColorBrush(Colors.White);
twitMessage.TextWrapping = TextWrapping.Wrap;
_twitMessage = twitMessage;
... other controls initialized...
twitTextPlaceholder = implementationRoot.FindName("twitStackPanelPlaceholder") as Canvas;
C1StackPanel sp = new C1StackPanel();
sp.IsHorizontal = false;
sp.ReplacePlaceHolder(twitTextPlaceholder, true);
sp.AutoSize = AutoSize.Both;
sp.Padding = new Thickness(5, 5, 2, 5);
sp.HorizontalAlignment = Alignment.Near;
sp.VerticalAlignment = Alignment.Near;
sp.ChildSpacing = new Size(2, 0);
sp.Children.Add(twitMessage);
}
VB:
''' <summary>
''' Builds third party controls dynamically at runtime
''' </summary>
Private Sub CreateComponentOneControls()
Dim twitMessage As New TextBlock()
twitMessage.Width = 290
twitMessage.FontSize = 11
twitMessage.Foreground = New SolidColorBrush(Colors.White)
twitMessage.TextWrapping = TextWrapping.Wrap
_twitMessage = twitMessage
...other controls initialized ...
twitTextPlaceholder = CType(implementationRoot.FindName("twitStackPanelPlaceholder"), Canvas)
Dim sp As New C1StackPanel()
sp.IsHorizontal = False
sp.ReplacePlaceHolder(twitTextPlaceholder, True)
sp.AutoSize = AutoSize.Both
sp.Padding = New Thickness(5, 5, 2, 5)
sp.HorizontalAlignment = Alignment.Near
sp.VerticalAlignment = Alignment.Near
sp.ChildSpacing = New Size(2, 0)
sp.Children.Add(twitMessage)
End Sub
Control library (TwitterSL.Common): The custom control library contains just one object: TwitControl. An instance of this control is dynamically created for each Tweet returned from Twitter. The control is then inserted at runtime into the parent Tweet container. Take a look at the XAML of this control to see how some simple animation storyboards can be tied to each control and wired up to individual control events.
Web project (TwitterSLServer): The web site project contains a single web page which hosts the Silverlight container. The project has been linked to the Silverlight project, and the default.htm and Page.xaml objects have been copied to the site. The web project is set as the startup project, but remember all of the "work" is done within the TwitterSL Silverlight project.
Proxy web service (TwitterWebService.asmx): The local TwitterWebService .asmx is part of the TwitterSLServer web project. This is the proxy service used to contact the Twitter API directly. The web service allows for async behavior by providing each public method with a BeginXXX() and EndXXX() variant. The Silverlight project can call BeginXXX() and continue processing; the EndXXX() is invoked once the request is completed by Twitter and the proxy web service.
Twitter API: Twitter provides a Representational State Transfer (RESTful) service to allow third-party applications to access the Twitter message exchanges. The API calls utilize HTTP Basic Authentication delivered via HTTP Requests to specified URLs, and returns back a list of messages in the desired format (XML, JSON, etc). The proxy web service delivers an XML snippet back to the Silverlight calling code for parsing and display. You can see how a request is created in the proxy web service methods below:
C#:
[WebMethod]
public string GetArchive(string username, string password)
{
try
{
return GetRequest(string.Format(@"http://twitter.com/statuses/user_timeline/{0}.xml", username), username, password);
}
catch (Exception ex)
{
throw ex;
}
}
private string GetRequest(string uri, string username, string password)
{
WebRequest request = HttpWebRequest.Create(uri);
if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
{
request.Credentials = new NetworkCredential(username, password);
}
WebResponse res = request.GetResponse();
StreamReader stream = new StreamReader(res.GetResponseStream());
string data = stream.ReadToEnd();
stream.Close();
return data;
}
VB:
<WebMethod()> _
Public Function GetArchive(ByVal username As String, ByVal password As String) As String
Try
Return GetRequest(String.Format("http://twitter.com/statuses/user_timeline/{0}.xml", username), username, password)
Catch ex As Exception
Throw ex
End Try
End Function
Private Function GetRequest(ByVal uri As String, ByVal username As String, ByVal password As String) As String
Dim request As WebRequest = HttpWebRequest.Create(uri)
If Not String.IsNullOrEmpty(username) AndAlso Not String.IsNullOrEmpty(password) Then
request.Credentials = New NetworkCredential(username, password)
End If
Dim res As WebResponse = request.GetResponse()
Dim stream As StreamReader = New StreamReader(res.GetResponseStream())
Dim data As String = stream.ReadToEnd()
stream.Close()
Return data
End Function
Putting it together
In the TwitterSL.Page class, the action kicks off when the user enters a Twitter username/password, and presses the "Get" button. The dropdown beside it determines which web request type will be issued. An AutoRefresh toggles, of course, the auto refreshing of the current message list. The line under "AutoRefresh" fades until the refresh occurs, one of the simple animations added to the XAML.

The Get button's click event trickles down to the GetWebRequest method, which calls the appropriate proxy web service method. Notice the call here using the "Begin" prefix, and passing a new AsyncCallback object to invoke the service asynchronously. The callback object specifies GetWebRequestResult as the target when the call finishes.
C#:
_twitterWebService.BeginGetTwits(username, password, new AsyncCallback(GetWebRequestResult), null);
VB:
_twitterWebService.BeginGetTwits(username, password, New AsyncCallback(AddressOf GetWebRequestResult), Nothing)
The web service simply sets up the appropriate url, builds an HTTP web request with authentication (if required), and issues the call (nothing too shocking here, but take a look at the code if you're not familiar with building up a web request).
Once the web service work is done, we're asynchronously delivered to the previously mentioned GetWebRequestResult method. This drops us into LoadTwits, which does the dirty work of parsing the returned XML snippet, creating new instances of the TwitControl for each message element and adding them to the parent container.

It's here, however, where the simplistic beauty of RESTful interfaces show their harsh side: we're pretty dependent on their format, and this parsing code could easily break. Also, of course, the REST won't give us strong typing. Hey, this would be a good place for a wrapper project, a la the Facebook Developer Toolkit. And speaking of enhancements....
Challenges to you
The fun & frustration of coding with new technology is overcoming the limitations of a limited feature set. The Twitterlight project is ripe for feature development in the coming months, as the Silverlight 2.0 Beta releases and control toolsets continue to emerge. Some challenges include:
- The TwitControl needs rich text support, to parse any urls into into clickable hyperlinks. Currently links show below the message as "Follow Link"
- Add more user credential security vs. current Basic Authentication
- Incorporate new toolset and SIlverlight features as released
Bio
Steve Holstad is a software development consultant for
Clarity Consulting, based in Chicago, IL. Check out
his blog for other writings and contact information.