RSS Feed


Witty: Creating a .Net Twitter API

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.

  1. Make the code simple, easy to understand, and easy to use
  2. 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.

image

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

 
Posted by Alan Le | 19 Comments | Trackback Url | Bookmark with:        
Tags:

Links to this Post

Comments

Thursday, 17 Jan 2008 11:32 by Proxy Server
<div class=ExternalClassBC60AD7267FE4A27827647C47D76FFC9><div>I was looking at using this API in a tool I am developing. It does not seem to support accessing Twitter through proxy servers. Or am I not looking properly?</div></div>

Thursday, 17 Jan 2008 11:40 by Re: Witty: Creating a .Net Twitter API
<div class=ExternalClassD741790B0AC34AB39B630428613C9E0B>That is correct Vasanth. There are plans to add proxy configuration in. You can check out the code by Jay Smith at: http://code.google.com/p/wittytwitter/issues/detail?id=27&amp;q=proxy</div>

Thursday, 17 Jan 2008 09:40 by Re: Witty: Creating a .Net Twitter API
<div class=ExternalClassFFC321A1287D4D169179D9877ABC99EB><div>Thanks. I will check out the code by Jay.</div></div>

Sunday, 3 Feb 2008 10:42 by Re: Witty: Creating a .Net Twitter API
<div class=ExternalClass030209AC09CE4B2389A9CCBB00E4070B><div>Here is a link to the post about the <a href="http://www.vasanth.in/2008/01/23/WorkingOnInkTweet.aspx">application I am developing</a>. One thing I noticed is that when I post using the TwitterLib the posts shows up as &quot;from witty&quot;. I wanted it to appear as &quot;from Twink&quot;. </div> <div> </div> <div>I found that the API does not porvide this as a configurable option. I was able to get the source from Google Code and make the change. </div> <div> </div> <div>I just want to run it by you to see if this is acceptable. I can make the change available to you.</div> <div> </div> <div>Please let me know. Thanks for the API.</div></div>

Monday, 4 Feb 2008 11:33 by Re: Witty: Creating a .Net Twitter API
<div class=ExternalClassB9A67B69753B49A1B78F10D512449B56>Hi Vasanth Your app is cool! Working with Ink is always so much fun. about the &quot;from witty&quot; text. it is based on the source parameter when sending tweets. I just updated the twitterlib to make a ClientName property that you can use to set the source. To get your client to show up as &quot;from Twink&quot;, you will also need to contact email alex@twitter.com with the name, URL, and description of your application. Hope this helps</div>

Monday, 4 Feb 2008 01:40 by Thanks
<div class=ExternalClassBABE3AB9AA4446D6A21DBADE68DD40D3>Thanks a lot for the update. Really appreciate it. And thanks for the tip about sending the mail to Alex.</div>

Wednesday, 27 Feb 2008 03:32 by Creating a .NET Twitter app
<div class=ExternalClassD189321E54234813B2E5960E12E0E3A7>Hi! Thanks for you work! Your Twitter API is very interesting ;-). About this one, is it possible to use your API to developp my own application?? Thanks for answer. Bastien</div>

Thursday, 14 Aug 2008 12:34 by angus
<div class=ExternalClass80D44BCA886840F38F3AE71826CB242F>Cool site.</div>

Sunday, 17 Aug 2008 09:00 by cool converters
<div class=ExternalClass27929E104D72458080109DBEBD5FE6B1>Here you can find cool converers.</div>

Thursday, 21 Aug 2008 08:17 by vine from texas
<div class=ExternalClass009254C0DF9D4C87A59547C31D89DDB9>Vine from texas is one of the best.</div>

Monday, 8 Sep 2008 02:49 by Net Framework Development
<div class=ExternalClass7AA9CB93A1BB4A239F9D2B7F7BF54C34>Nice post on Creating a .Net Twitter API.... great help... keep it up </div>

Tuesday, 20 Jan 2009 12:51 by Michael
<div class=ExternalClassD99E236C89BE4E65B186432E9F07B074>Thanks Alan for the lib - very useful :) One question: it seems there is no way to retrieve ALL tweets from a user (after a certain date), I'm only ever getting 20 and I see no 'page'-param. Am I missing something?</div>

Sunday, 10 May 2009 02:26 by ASP.NET development
<div class=ExternalClass69CD75828F10458A8F1BB070A95F2C7D>Nice work here - like the idea of implementing INotifyPropertyChanged and ObservableCollection. I have always found the Visual Studio xsd tool to be pretty unhelpful, particularly for large classes. It's okay for something quick and dirty but it does generate code that is difficult to maintain. Did you consider implementing custom serialisation for the Twitter responses rather than using the XML DOM?</div>

Friday, 29 May 2009 11:33 by srdha
<div class=ExternalClassB252DEC81C7742D180E71E086543F70A>i gust want to say some thing &quot;great job&quot; Update your Twitter randomly according to your intrest Or, from Rss Feed Or, from your own tweet message list Or, Any combination of the above three http://feedmytwitter.com</div>

Wednesday, 8 Jul 2009 07:58 by wow gold
<div class=ExternalClassC90C6E65D521462296B33265121506D1>http://www.inwowgold.com/ http://www.inwowgold.com/Final-Fantasy-XI-Gil/ http://www.inwowgold.com/power-leveling/ http://www.inwowgold.com/sell-wow-gold/ 09.07.09T</div>

Sunday, 19 Jul 2009 01:09 by apuestas
<div class=ExternalClassFE838BCCE0044DDF831F98965A988E76>http://www.apuestasdeportivaseu.com/</div>

Sunday, 19 Jul 2009 01:10 by apuestas
<div class=ExternalClass5166FA720BE54643887BD2342C1350C0>hjklčlol</div>

Wednesday, 22 Jul 2009 02:54 by wow gold
<div class=ExternalClass172F4EBD50CB47579C746ABEAE994A07>Discover the Colossal Regigigas – receive the 486th Pokémon to Pokémon Diamond, Pokémon Pearl or Pokémon Platinum exclusively at the Pokémon Village Fête. With this special Regigigas in your party in Pokémon Platinum, you may stumble across Electronic Theatre ImageRegisteel, Regice and Regirock during your adventure,In addition you can also enjoy face painting, balloon modelling and have your photo taken with your favourite Pokémon character. </div>

Monday, 24 Aug 2009 03:04 by zhang
<div class=ExternalClassDB271C48D1134E478A9F28086890D22E>The years <a href="http://www.tiffanyhotsale.com" title="Tiffany Bracelet">Tiffany Bracelet</a>have smudged<a href="http://www.tiffanyhotsale.com" title="Tiffany Earrings">Tiffany Earrings</a> bitterly and<a href="http://www.tiffanyhotsale.com" title="Tiffany rings">Tiffany rings</a> astringently for<a href="http://www.tiffanyhotsale.com" title="Tiffany jewellers">Tiffany jewellers</a> the good <a href="http://www.tiffanyhotsale.com" title="Tiffany jewelry">Tiffany jewelry</a>people, also<a href="http://www.tiffanyhotsale.com" title="Tiffany jewellery">Tiffany jewellery</a> gave the <a href="http://www.tiffanyhotsale.com" title="Tiffany silver">Tiffany silver</a>people who<a href="http://www.ghdbeauty.com" title=ghd>ghd</a> loved really <a href="http://www.ghdbeauty.com" title="GHD Dark">GHD Dark</a>to increase <a href="http://www.ghdbeauty.com" title="ghd straighteners">ghd straighteners</a>the move,<a href="http://www.ghdbeauty.com" title="ghd hair straighteners">ghd hair straighteners</a> the true, <a href="http://www.ghdbeauty.com" title="ghd hair styler">ghd hair styler</a>the good <a href="http://www.ghdsale.com" title="Cheap GHD">Cheap GHD</a>and the <a href="http://www.ghdsale.com/ghd-pure-70.html" title="GHD pure">GHD pure</a>beautiful are<a href="http://www.ghdsale.com/ghd-kiss-69.html" title="GHD kiss">GHD kiss</a> the life <a href="http://www.ghdsale.com/ghd-mk4-black-66.html" title="GHD MK4 Black">GHD MK4 Black</a>sincere song<a href="http://www.ghdsale.com/ghd-mk4-pink-67.html" title="GHD MK4 Pink">GHD MK4 Pink</a> of praise, but <a href="http://www.ghdsale.com/ghd-mk4-glod-68.html" title="GHD MK4 Gold">GHD MK4 Gold</a>this song <a href="http://www.ghdsale.com/ghd-purple-71.html" title="GHD Purple">GHD Purple</a>of praise's <a href="http://www.edhardysale.net" title="don ed hardy">don ed hardy</a>source, was<a href="http://www.edhardysale.net" title="ed hardy shoes">ed hardy shoes</a> my mother.<a href="http://www.edhardysale.net" title="ed hardy apparel">ed hardy apparel</a> She who <a href="http://www.edhardysale.net" title="ed hardy men">ed hardy men</a>struggles in<a href="http://www.edhardysale.net" title="ed hardy women's">ed hardy women's</a> the misery<a href="http://www.edhardysale.net/bags-c-11_14_24.html" title="ed hardy bag">ed hardy bag</a> sings the <a href="http://www.edhardysale.net/tshirts-c-11_39.html" title="ed hardy tshirt">ed hardy tshirt</a>song attentively, <a href="http://www.uggbootsdirect.com" title="ugg boots">ugg boots</a>is song <a href="http://www.uggbootsdirect.com" title=uggs>uggs</a>of the <a href="http://www.uggbootsdirect.com" title="wholesale ugg boots">wholesale ugg boots</a>life, is <a href="http://www.uggbootsdirect.com" title="ugg sheepskin boots">ugg sheepskin boots</a>the agreement,<a href="http://www.hohotrade.com" title="china wholesale">china wholesale</a> but not <a href="http://www.hohotrade.com/digital-cameras-wholesale-8_44.html" title="wholesale digital cameras">wholesale digital cameras</a>shed optimistic<a href="http://www.hohotrade.com/mp4-players-accessories-wholesale-13_105.html" title="mp4 watches">mp4 watches</a> spirit. very <a href="http://www.hohotrade.com/mp4-players-accessories-wholesale-13_105.html" title="Wholesale Mp4">Wholesale Mp4</a>long period <a href="http://www.hohotrade.com/shirts-tops-wholesale-11_72.html" title="wholesale t shirts">wholesale t shirts</a>of time, <a href="http://www.disnet1.org" title="Wholesale handbags">Wholesale handbags</a>we rely <a href="http://www.disnet1.org" title="wholesale clothing">wholesale clothing</a>on the<a href="http://www.disnet1.org" title="Wholesale jewelry">Wholesale jewelry</a> mother to <a href="http://www.disnet1.org" title=wholesale>wholesale</a>live, looks<a href="http://www.ememe.net" title="Wholesale Jewelry">Wholesale Jewelry</a> like in <a href="http://www.ememe.net" title="Wholesale fashion jewelry">Wholesale fashion jewelry</a>the river <a href="http://www.ememe.net" title="Wholesale costume jewelry">Wholesale costume jewelry</a>the fish<a href="http://www.chihairshop.com" title=chi>chi</a> leaves the <a href="http://www.chihairshop.com" title="chi flat iron">chi flat iron</a>boiling water<a href="http://www.chihairshop.com" title="chi hair products">chi hair products</a> not to<a href="http://www.chihairshop.com" title="chi irons">chi irons</a> be dissimilar.<a href="http://www.chihairshop.com" title="buy a chi iron">buy a chi iron</a> In the<a href="http://www.chihairshop.com" title="cheap chi iron">cheap chi iron</a> morning, the <a href="http://www.chihairshop.com" title="chi ceramic irons">chi ceramic irons</a>day has not put brightly, she prepared the breakfast which we went to school, underground went early. </div>

Name:
URL:
Email:
Comments:

CAPTCHA Image Validation