Introducing Flxt.it, Powered By Twilio & AppHarbor

flxt512

A few weeks ago a challenge came across my Twitter stream – build an application that combines Twilio, a cloud communication platform, with AppHarbor, the easiest way to deploy and host .NET applications. This seemed like the perfect fit for an idea that’d been bouncing around in my head for some time. Five days later,  long after the Super Bowl ended, I submitted my entry.

Yesterday morning another tweet popped up on my desktop…my entry won!

And now…I’m proud to introduce Flxt.it – a simple tool to manage your Netflix queue.

The Idea

How many times have you been away from a computer and thought of a movie you don’t want to miss? This is where Flxt.it comes in – if you can send a text message, you can add movies to your Netflix queue. There are existing applications to accomplish this, but sending a text message is faster, and you don’t need a smart phone.

The Implementation

When you sign up for Flxt.it, your Netflix account is linked to your cell phone, and you’re given a phone number to send movie titles to. This number is provided by Twilio and it’s where the magic begins.

When Twilio receives a text message, it sends the information on to the web application, which is running ASP.NET MVC 3. In Flxt.it there is a single endpoint that receives the message, looks up your Netflix account information, takes care of business, and responds with a text message to let you know the movie was added to your queue.

public class Message
{
	public string AccountSid { get; set; }
	public string Body { get; set; }
	public string From { get; set; }
	public string FromCity { get; set; }
	public string FromCountry { get; set; }
	public string FromState { get; set; }
	public string FromZip { get; set; }
	public string SmsSid { get; set; }
	public string To { get; set; }
	public string ToCity { get; set; }
	public string ToCountry { get; set; }
	public string ToState { get; set; }
	public string ToZip { get; set; }
}

[ValidateTwilioSignature("YourTwilioAuthToken")]
public class SmsController : TwilioController
{
	[HttpPost]
	public ActionResult Search(Message message)
	{
		var user = db.Single<User>(u => u.PhoneHash == message.From.NormalizeAndHash());
		var movie = netflix.Search(message.Body, user.NetflixApiToken);
		if (netflix.AddToQueue(movie, user.NetflixApiToken))
			return Sms("{0} has been added to your queue!", movie.Title);

		return Sms("Unable to add to your queue.");
	}

	protected override void OnException(ExceptionContext filterContext)
	{
		Log.Write(filterContext.Exception);
		filterContext.Result = Sms("Whoops! Something went wrong. Please try again later.");
		filterContext.ExceptionHandled = true;
	}
}

MVC’s model binding turns all the parameters Twilio sends into an easy to use class. To respond to the incoming message there are two options – TwiML or REST. The former is the only option if you want to do more than one action, like send multiple SMS messages and redirect to another TwiML document. The later is the easier option when you just want to send a response – set your response’s content type to text/plain and Twilio will send the response body to the sender as an SMS message!

This was the approach used by Flxt.it. A custom SmsResult sets the content type and makes sure that the message doesn’t exceed 160 characters. If you don’t want to send a reply message simply send an empty response.

It’s also important to handle any errors properly so that Twilio always gets a valid response from your application. MVC makes this crazy easy without needing to wrap your entire action in a try/catch. By either overloading the OnException method or providing a custom filter to the action or controller you can return an SmsResult no matter what happens during the action.

Security & Privacy

We are all concerned about privacy, so handling phone numbers should not be taken lightly. Even in a simple application like this I want to take every precaution to keep users’ phone numbers safe.

The first, and most effective, precaution is Flxt.it does not store the full phone numbers. Because Flxt.it will always be responding to incoming messages, it will store a hash of the phone number and the last four digits and still be able to link your Netflix account to your incoming movie request.

The second way to protect the Twilio endpoint is to ensure that Flxt.it will respond to requests from Twilio and nobody else. In every request, Twilio will sign the request using your secret authentication token and send it in a HTTP header. To validate it you perform the same operation and if the request is valid you will get the exact same value.

The following is an example of how you can create an action filter in MVC to easily validate an action or every action in a controller. It’s based on John Sheehan’s most excellent presentation at mvcConf last week.

[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)]
public class ValidateTwilioSignatureAttribute : ActionFilterAttribute
{
    public ValidateTwilioSignatureAttribute(string authToken)
    {
        authToken.ThrowIfNullOrEmpty("authToken");

        AuthToken = authToken;
    }

    public string AuthToken { get; private set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var request = filterContext.HttpContext.Request;

        var fullUrl = String.Format("http://{0}{1}", request.Url.Host, request.Url.PathAndQuery);
        var valueToHash = new StringBuilder(fullUrl);

        if (request.HttpMethod == "POST")
        {
            var sortedParams = request.Form.AllKeys.OrderBy(p => p).ToList();
            foreach (var param in sortedParams)
            {
                valueToHash.Append(param);
                valueToHash.Append(request.Form[param]);
            }
        }

        var sha1 = new HMACSHA1(Encoding.UTF8.GetBytes(AuthToken));
        var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(valueToHash.ToString()));

        var encodedHash = Convert.ToBase64String(hash);

        var twilioSignature = request.Headers["X-Twilio-Signature"];

        if (encodedHash != twilioSignature)
            filterContext.Result = new HttpForbiddenResult();
    }
}

One thing to note here is that when you are in a load-balanced environment like AppHarbor the web server your request is being served by is likely not the exact address that Twilio calls from the outside. Since it is part of the signature we need to be sure to use the host header value and not the raw URL as seen by ASP.NET.

Couldn’t Be Easier

In Flxt.it I’m barely scratching the surface of Twilio’s capabilities. In addition to sending and receiving SMS messages, they have an incredibly powerful platform for making and receiving phone calls. Best of all it’s available on a pay as you go basis – no contracts! You no longer need to be a Twitter-sized company to be able to add phone and SMS capabilities to your application.

Go ahead and try it out for yourself – you get $30 worth of credits just for signing up!

Moving On Up To The Cloud

For the last year I’ve been hosting this site on a server running in my basement. While it’s been a much better experience than the $6/month, ‘everything included’, shared hosting plan I was on before, this setup has had its own set of problems. For starters, cable internet is not a viable way to host web sites. Even with a commercial grade, unshared, 10/1Mbps connection the response time to my site was quite high and fluctuated wildly. To make matters worse, we apparently live in a neighborhood that doesn’t have much redundancy on the local power grid – we’ve have numerous power outages in the year we’ve lived here.

While this might be acceptable for a simple blog, I recently started hosting a few sites for others, including our local .NET Users Group and a neighbor’s business site, and the performance and uptime bar needed to be cranked up a bit. I needed something that was on a good, solid internet connection, gave me plenty of control, and was priced low enough to address the wife acceptance factor.

My new home: The Rackspace Cloud

After considering a variety of options, I finally settled on Rackspace’s Cloud Servers. I’d been tinkering with their services for some time and had been very impressed not only by the performance and capabilities, but by the price. For as little as $11 per month you can run your very own virtual Linux server with 256MB of RAM and 10GB of disk space. Need Windows servers? They start at about $29 per month for 512MB of RAM and 20GB of disk space. Need some short-term servers to handle capacity? You pay by the hour and there are no minimums or commitments! Their control panel is incredibly easy to use, and for more advanced scenarios there’s even an API for automatically scaling up and down. I could go on, but instead I’m going to recommend an excellent review at Social Cloud Now.

For my little setup I went with 2 Ubuntu servers and 1 Windows server – total damage is just over $50/month. This gives me an Apache web server, an IIS web server, and keep the database on its own machine. How does it perform? I think my Pingdom response time report says it all.

Pingdom 

Moving up to the Rackspace cloud has cut my response time in half! Before the move my response time averaged close to 800ms, after it’s under 400ms (the brief spike was after I had migrated the database to the cloud but before I had migrated the web server). Those are the worldwide numbers – the US average is only 170ms!

A perfect fit

I couldn’t be happier with my move to the Rackspace cloud. Having great performance and availability, being easy to use, and affordably priced makes Rackspace my cloud provider of choice.

Weekly Web Nuggets #84

Pick of the week: Why Do Big Companies Suck?

General

Web Development

Weekly Web Nuggets #83

Pick of the week: Responsible Open Source Code Parenting

General

Web Development

Speed Up The ASP.NET Development Server

Visual Studio has had a built-in web server for years, but I’m apparently one of the few developers that still prefers IIS. Why? It’s certainly not more convenient – you have to setup a virtual directory, file system permissions, and change the debugging options. It’s because on a modern Windows OS (Vista or newer) it is so slooooooooow!

Take a look at the following Firebug stats:

Sloooooooooow

There is literally no content on this page yet. I’ve got two static resources coming from the site, and I’m using the Google AJAX loader to pull in jQuery and the Maps API. Yet while even the slowest resource from Google takes a scant 144ms to load, the page and resources I’m pulling from my local machine are each taking just over a second!

Further testing showed that where Firefox and Chrome both exhibit this behavior, IE8 did not (or at least not by my seat-of-the-pants testing – the IE developer tools still don’t have a network profiler). Even stranger is that if I connect using 127.0.0.1 or localhost. (notice the trailing .) things improved!

Something isn’t right here.

The Culprit: IPv6 and DNS

With Windows Vista, Microsoft included the IPv6 networking stack by default. Under Windows 7 (and probably Vista) they’ve apparently left resolution of localhost up to DNS. As far as I can tell the slowness isn’t the browsers’ fault, but rather the system trying to resolve localhost using IPv6.

Fortunately the fix is easy. Fire up Notepad (or your text editor of choice) as an Administrator, and open up your system’s hosts file (typically C:\Windows\System32\drivers\etc\hosts). You should see that all entries are commented out. Simply uncomment (remove the #) from the IPv4 localhost entry only, save the file, and restart your browser.

hosts

Once this is done, things look much, much better when using Visual Studio’s development server. As we’d expect, the local resources are significantly faster than the external ones.

Fast

Weekly Web Nuggets #82

Pick of the week: Version 1 Sucks, But Ship It Anyway

General

Web Development

Weekly Web Nuggets #81

Pick of the week: Figuring Out What Your Company Is All About

General

Web Development

Weekly Web Nuggets #80

Pick of the week: Understanding Public Clouds: IaaS, Paas, & SaaS

General

  • VS 2010 and .NET 4.0 Beta 2: Scott Guthrie announces the highly anticipated Beta 2 of Visual Studio 2010 and .NET 4.0. In additional to all the great new stuff coming in 4.0, Beta 2 includes a go-live license!
  • Mapping From IDataReader/IDataRecord with AutoMapper: Jan Van Ryswyck shows how you can use AutoMapper to help alleviate a lot of the tedious, repetitive code typically needed with straight ADO.NET.
  • Treating User Myopia: Jeff Atwood offers some excellent UI design advice about how your users more than likely see your application.
  • LinqLite: Jason Allor has put together a library to help with writing your own Linq providers.
  • Using a Personal Kanban Board: Peter Microserf tells us how using a personal kanban board has helped him get organized and get things done.

Web Development

Weekly Web Nuggets #79

Pick of the week: Software Externalities

General

Web Development

Weekly Web Nuggets #78

Pick of the week: An Engineer’s Guide to Bandwidth

General

Web Development