In the process of writing Witty, I created my own .Net wrapper class library for the Twitter API. I wanted to share my experience created this class library, which I named TwitterLib.
I had two goals in mind when writing TwitterLib.
- Make the code simple, easy to understand, and easy to use
- Make use of PropertyChange Notification and ObservableCollection
First attempt using XSD
The Twitter API can present data as XML or JSON. I'm more familiar on working with XML in .NET than JSON, so I picked the XML format.
In my first crack at it, I use the XSD tool to create the Twitter .NET classes from the XML output. I used the Visual Studio Command Prompt with the command "xsd http://twitter.com/statuses/public_timeline.xml". This generated an public_timeline.xsd file. Next, I used the xsd command again "xsd public_timeline.xsd /c" to create the 3 twitter classes: statuses, statusesStatus, and statusesStatusUser. I
While functional, I ran into a few issues with the auto-generated classes. I didn't like the names given for the classes. In addition, the classes were littered with XML related attributes that made the code seem messy. I changed the classes to implement INotifyPropertyChanged, when the twitter API had a change, I had to re-generate the classes losing changes that I made. I went the partial class route for each of the classes but I think that added unnecessary complexity. I wanted to abstract the classes more from the XML sent from Twitter. In the end, I started from scratch.
My Twitter .NET Classes
I created three main classes: Tweet, User, and DirectMessage.
- Tweet: Represents the status post for a Twitter User.
- User: A Twitter User
- DirectMessage: Represents a message sent to a User
These classes implement the INotifyPropertyChanged Interface, so that any property change will get propagated to the controls bound to the property. I also created collection classes for these classes that inherit from ObservableCollection. WPF binding rely heavily on these two features so it was important for my classes to have them. For example, whenever the the Witty client is refreshed, I update the RelativeTime; the TextBlock bounded to display this property will show the new time.
I created a TwitterNet class to simplify web requests to the TwitterAPI for populating the aforementioned classes. TwitterNet acts as the main wrapper for interacting with the Twitter API.
For example, to get the friends timeline for an authenticated user:
TwitterNet twitter = new TwitterNet(username, password);
TweetCollection tweets = twitter.GetFriendsTimeline();
Behind the scenes, TwitterNet does the heavy lifting of creating the web requests as well as parsing the html. All timeline requests route to a private method call RetrieveTimeline. Here's a snippet at the meat of the RetrieveTimeline method. You can see the full code for TwitterLib on the Witty Source page.
// Get the Web Response
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream());
// Load the response data into a XmlDocument
XmlDocument doc = new XmlDocument();
doc.Load(reader);
// Get statuses with XPath
XmlNodeList nodes = doc.SelectNodes("/statuses/status");
foreach (XmlNode node in nodes)
{
Tweet tweet = new Tweet();
tweet.Id = double.Parse(node.SelectSingleNode("id").InnerText);
tweet.Text = HttpUtility.HtmlDecode(node.SelectSingleNode("text").InnerText);
string source = HttpUtility.HtmlDecode(node.SelectSingleNode("source").InnerText);
if (!string.IsNullOrEmpty(source))
tweet.Source = Regex.Replace(source, @"<(.|\n)*?>", string.Empty);
string dateString = node.SelectSingleNode("created_at").InnerText;
if (!string.IsNullOrEmpty(dateString))
{
tweet.DateCreated = DateTime.ParseExact(
dateString,
twitterCreatedAtDateFormat,
CultureInfo.CurrentCulture, DateTimeStyles.AllowWhiteSpaces);
}
User user = new User();
XmlNode userNode = node.SelectSingleNode("user");
user.Name = userNode.SelectSingleNode("name").InnerText;
user.ScreenName = userNode.SelectSingleNode("screen_name").InnerText;
user.ImageUrl = userNode.SelectSingleNode("profile_image_url").InnerText;
user.SiteUrl = userNode.SelectSingleNode("url").InnerText;
user.Location = userNode.SelectSingleNode("location").InnerText;
user.Description = userNode.SelectSingleNode("description").InnerText;
tweet.User = user;
tweets.Add(tweet);
}
tweets.SaveToDisk();
}
A few additional classes were created to round out TwitterLib.
- StringHelper: String related static methods, such as extracting hyperlinks
- TinyUrlHelper (added by lazycoder): Wrapper for interacting with TinyUrl API
- Timeline: Enumeration of available Twitter timelines
- RateLimitException: Custom Exception when the 70/hour rate limit for authenticated Twitter API calls have been hit.
Here's the class diagram for TwitterLib.
With the TwitterLib in place, I turned my attention to the UI and created the main WPF app. The TwitterLib made it easy to interact with calls to Twitter as well as bind my controls and DataTemplates to twitter objects. Look for a post about the it sometime soon.
You can use the TwitterLib if you want to make your own WPF twitter client or Twitter visualization. You can get the source for TwitterLib as well as Witty on the Witty Google Code project page.
Related Posts:
Creating a .NET Twitter API in 4.5 seconds - by Karsten Januszewski
Silverlight: Creating a Twitter Client Part 1 - by Rob Conery