Sunday, April 24, 2011

Roll your own Text Messaging Apps with Twilio and MVC 3

I've been messing around with Twilio and their awesome set of TwiML API's this weekend and made a fun little C# Twilio library for creating simple text (and voice) based applications from MVC 3 sites.

How Twilio's TwiML API Works

Twilio-overview

An SMS comes in to one of your Twilio Phone Numbers.
Twilio Makes a POST or GET call to a URL you set up.
Your site provides a TwiML Response that Twilio parses and executes.

(See Twilio's own how it works page for a way better explanation.)




Using TwilioSharp to Send TwiML Responses From MVC

As part of my handy dandy TwilioSharp helper library I've created a base TwiML Controller for easily creating TwiML Responses with a Fluent TwiMLBuilder Class.  

The TwiML Controller exposes a TwiML method that is meant to emulate the ease of use of the Json method available in all MVC Controllers.  The TwiML method takes a Func<TwiMLBuilder, TwiMLBuilder> that acts as your Response Factory method; this makes building complex responses easier by allowing for in line fluent declarations.




Full Fledged Example

You can view a full fledged Magic 8-Ball Answerizer 3000 example on GitHub (which is also live on AppHarbor until I run out of money in my Twilio Account).  Including a more in depth example of using the Fluent TwiMLBuilder for answering phone calls.


8ballapp

Tuesday, April 12, 2011

MVC 3 Long Polling / "Comet" Chat Example

I recently read a great article on WebSocket alternatives in MVC by Clay Lenhart and decided to write up a quick proof of concept Chat Server Example for .Net MVC.  Here is a quick run-down of what I did.

First, read up on Comet; a basic way to have real-time notifications sent to a browser (like push notifications).  One common Comet technique involves "Long Polling" an http connection.  What this means is that we call out to a URL that expects to wait around for a long time before something happens.


Pubsub_poll


Pubsub_longpoll




The Long Poll Chat Async Controller

The first step for the chat server was to create a new Async Controller (Async what? Check out this great introduction to Async Controllers) to handle our Long Poll requests.  Here is the ChatController I created:

You can see that we've created our Index action as an Async that calls our to our ChatServer and checks for a message to arrive.  By default, I've specified a 60 second time limit before returning an empty list of messages, but you could theoretically let this go on for hours waiting for a response.  Once a response comes back from the ChatServer, we tell the AsyncManager we are done and return our messages in JSON form.


The ChatServer

I chose to use Observables and the Reactive (Rx) Framework to have a synchronized way of notifying all interested parties when a new message comes in.  To do this, I took advantage of the Subject<T> class that wraps a lot of the Observable and Observer implementation details.  To handle persisting my chat history, I use a simple Queue to keep the last 100 or so by default.  Whenever a new message comes in, I check the history length and pop off anything over the limit, then push in my new messages.  Yes, eventually I'd have to figure out a strategy for pushing this back to a database or Redis cache server thingy but this is just a demo, so relax.



The Client Side (HTML and JS)

On the client side, we need to take advantage of some of jQuery's helper methods for POSTing to an MVC Action (the Index Action on the Chat Controller in our case).  We are going to make a POST call to /Chat that will sit around until a new message arrives, or our 60 second timeout is reached.  If a new message comes in, our POST call will return immediately with the new message(s).  From there, we just insert them into our current chat history.



See It In Action



Example


I've uploaded the MVC Chat Example to AppHarbor for people to play around with.  You can also download the sample project from my dropbox account, or view the source at the MVCChatSite Project page on BitBucket.