Posted on May 13th, 2011
Scott Hanselman recently posted about fixing the code on his site that would display his most recent tweet by consuming the Twitter Json API directly from JavaScript and Dave Ward provided some great input in the comments on the architecture of the Twitter Json API feed. There was a brief mention about hitting the API from the server side. I decided to write a post about it. Wanna' hear it? Here it goes!
Lets take a look at how we can write a controller action in ASP.NET MVC3 that will provide us with some additional functionality for working with the Twitter Json API to retrieve user timeline tweets. Fire up an existing ASP.NET MVC 3 web project (if it uses the Razor view engine) or start with a new one. Create a new controller called TwitterController and a action method named UserTimeline that will take in a Twitter user screen name and a count for how many tweets to return.
using System.IO;
using System.Net;
using System.Web.Mvc;
namespace Website.Controllers
{
public class TwitterController : Controller
{
public ActionResult UserTimeline(string screenName, int count)
{
var result = string.Empty;
var baseTwitterApiUrl = "http://api.twitter.com/1/statuses/user_timeline.json";
var url = string.Format("{0}?screen_name={1}&include_rts=true&count={2}",
baseTwitterApiUrl, screenName, count);
var webRequest = WebRequest.Create(url);
webRequest.Timeout = 2000;
using (var response = webRequest.GetResponse() as HttpWebResponse)
{
if (response.StatusCode == HttpStatusCode.OK)
{
var receiveStream = response.GetResponseStream();
if (receiveStream != null)
{
var stream = new StreamReader(receiveStream);
result = stream.ReadToEnd();
}
}
}
return new ContentResult { Content = result, ContentType = "application/json" };
}
}
}
Lets break down what is going on in this method. First we create a local variable for our result string and build the Twitter API url. We have the baseTwitterApiUrl separated out so we can move that to some other location if we wanted to be able to modify it without having to edit this source code ('cause it will change, as Scott's post illustrates). After building the url string we instantiate a new WebReuqest object and set the Timeout property to 2000 milliseconds (2 seconds). There is no hard reason we set it to 2 seconds instead of 3 or 1 or whatever. We simply wanted to add a way to not have this call running forever if the Twitter API cannot be reached or is having issues. With our WebRequest object all set, we leverage the using syntax to make our call out to the Twitter API and get the response back. We do a quick check to verify that we receive a OK HTTP response and proceed to read the response stream into our local variable for our result. Finally, we return a ContentResult object from our method. We do this instead of using the JsonResult object because our result string is already a Json formatted string. The JsonResult object is designed to convert an object into a Json string.
Consuming the Json in our views is almost the same as consuming the Twitter api feed directly in JavaScript. I started with an empty MVC 3 project so I will add a HomeController with an Index action method and a corresponding Index.cshtml view so I have a "page" to hit and test out the code we will add. My solution tree looks like so:

Assuming we want to have the latest tweet at the top of all of our site pages, we will add the html and JavaScript to our Views/Shared/_Layout.cshtml file.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>@ViewBag.Title</title>
<link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
</head>
<body>
<h2>Latest Tweet from @@schwarty's Twitter Timeline</h2>
<span id="twitter_update_list"></span>
@RenderBody()
</body>
<script type="text/javascript" src="http://twitter.com/javascripts/blogger.js"></script>
<script type="text/javascript">
$(function () {
$.getJSON('/Twitter/UserTimeline', { screenName: 'schwarty', count: 1 }, twitterCallback2);
});
</script>
</html>
Twitter provides some JavaScript for parsing their Json data that we reference with the following tag:
<script type="text/javascript" src="http://twitter.com/javascripts/blogger.js"></script>
That script contains the twitterCallback2 JavaScript method. This method pushes HTML into a DOM tag with the id of twitter_update_list. Thus we needed to add that id attribute to the tag where we want our tweet to show. In our local JQuery document ready block we can use the $.getJSON function to hit our UserTimeline action and call the twitterCallback2 function upon completion. Notice that we are passing our screenName and count values in as a data block in the $.getJSON function instead of part of the url. We are doing this so that we didn't have to add a new route to our route collection. We can do an HTTP GET call and pass along a payload of data without including it in the GET url string. The ASP.NET MVC engine will handle mapping that data to the corresponding parameter variables with matching names automatically. Have I mentioned before how awesomesauce ASP.NET MVC is?
If we do an F5 we can see our code in action:

My latest tweet was actually a retweet, and we can see that the code is working to show those as well.
From here we could decorate our UserTimeline method with the OutputCache action attribute to cache our requests to Twitter.
using System.IO;
using System.Net;
using System.Web.Mvc;
namespace Website.Controllers
{
public class TwitterController : Controller
{
[OutputCache(Duration = 300, VaryByParam = "screenName")]
public ActionResult UserTimeline(string screenName, int count)
{
... same code as before ...
}
}
}
This would cache the results for 5 minutes based on the screenName parameter. When we call that action method repeatedly the result will be cached for that particular screenName. Thus we can reduce our calls out to the Twitter api and get a bit of a performance gain as well as have the architecture in place so we can quickly adapt to Twitter's limit to the number of calls per hour to that api if the need arises. You can test this by adding a break point in Visual Studio 2010 on the return line of the UserTimeline method then doing an F5 of the project and refreshing the browser several times. You will notice that the first load of the page will hit the break point, and the subsequent refreshes will not, unless you keep refreshing for more than 5 minutes! Also, if you change the screenName in the JavaScript to get someone else's timeline then you will notice that the break point will be hit again to initialize the caching of that specific request.
Damn, that sure was a lot of stuff to do compared to simply consuming the Twitter Json API feed via HTML and JavaScript! Although it does give us a little more control over how we work with the Twitter feed, and ultimately it was pretty easy to accomplish in MVC. In parting, I leave you with a couple of things to think about:
Since we are consuming the Twitter feed server side, we have the ability to log and diagnose issues with the request to Twitter. If you are using ELMAH to track site exceptions then you are probably already set up to be logging any issues that might occur in your call out to Twitter!
If you want to put this code into play on a public facing site you may want to consider locking down access to that action, otherwise someone may decide to use your cached version of the Twitter Json API for their own site.
No new comments are allowed on this post.
Discussion
hilton smith
i like it. a neat little solution to a very popular problem. and the output caching a small, clever touch i'd have overlooked.
Raj
Why we are creating this, if Twitter has some of their API`s free to download. So lets say, in my blog (from Wordpress) on the right nav I am showing my recent tweets. So I am guessing they are using this code???
Aidan
Thanks for this!
A the twitter account tweeted a new post while the user is on this page, is there any way for the posts to update on this page without a page refresh?
Justin Schwartzenberger