Building Twilio Apps Using ASP.NET MVC 4 Web API

November 08, 2012
Written by

Twilio Bug Logo
Developer Long Le

This is the second post in a two part series by Long Le, a .NET Enterprise Architect and Solutions Architect at Computer Sciences Corporation. You can read part one here. Long is an avid blogger and a serious Modern Warfare 3 Gamer. Make sure to follow his code and gaming conversations on Twitter @LeLong37, and check out his blog here.

Twilio has some pretty good documentation on developing with MVC using your traditional Controllers, Actions, and Views leveraging their REST Api’s. However this post will be for those that would like to develop around Twilio this using MVC’s new WebApi.

There are typically no Views being used when working with Twilio’s Platform (unless you are placing in-line code in your View’s markup), it’s largely a lot of REST like request’s that Twilio makes to your application and your application is responding with XML payloads, so that Twilio can injest your Xml payload and figure out what the next step is, whether it be a voice and/or SMS request.

So let’s get into it, the first thing we do is to get our MVC 4 app infrastructure ready.

In Global.asax.cs, let’s add some Uri path extensions, meaning our WebApi methods will know what type of content/type to deliver back from a request by the extension of the Url. For example if we have a inbound request for a collection of some sort mapped to http://localhost/api/MyController/MyPost.xml, the MVC runtime will know to return my collection in Xml vs. Json (MediaTypeFormatterExtensions.AddUriPathExtensionMapping).

    public class WebApiApplication : HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            MefConfig.RegisterMef();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            FilterConfig.RegisterHttpFilters(GlobalConfiguration.Configuration.Filters);
            MapperConfig.RegisterMappings();

            GlobalConfiguration
                .Configuration
                .Formatters
                .XmlFormatter
                .AddUriPathExtensionMapping("xml", "text/xml");

            GlobalConfiguration
                .Configuration
                .Formatters
                .XmlFormatter
                .AddUriPathExtensionMapping("json", "application/json");
        }
    }

Note: Technically, we only need the UriPathExtensionMapping for Xml, however just in case we ever decided to still want to serve up Json payloads from our WebApi methods we will go ahead and add one for Json as well. That way our Api methods can return either Xml or Json just by changing the extension on the url.

For example:

  • http://localhost/api/MyController/MyPost.xml, would return an xml collection
  • http://localhost/api/MyController/MyPost.json, would return a json collection

Update and/or add a WebApi route (in this case I’ll just replace the one that’s there since I don’t need the default route at all) so that we can support our added UriPathExtensionMappings we added earlier (.xml, .json).

Location: YourMvc4Project/App_Start/WebApiConfig.cs

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "Api with action and extension ",
                routeTemplate: "api/{controller}/{action}.{ext}/{id}",
                defaults: new {
                    id = RouteParameter.Optional,
                    ext = RouteParameter.Optional}
                );

            //config.Routes.MapHttpRoute(
            //    name: "DefaultApi",
            //    routeTemplate: "api/{controller}/{id}",
            //    defaults: new {id = RouteParameter.Optional}
            //    );
        }
    }

Now we can build a fictitious example of a Weather WebApi controller for Twilio to make requests to.

    • GatherZipCode method, will prompt a a voice caller for what zip code the caller is interested for weather information.
    • RetrieveWeather method, will actually read and speak the weather condition to the voice caller, obviously this is a an example and you would probably need to hit a real weather service such as Accuweather for real world purposes.

I prefer implementing it this way, because at the end of the day you end up with just small methods that handle responses to Twilio requests, and we get to use the TwilioResponse object to give us some assistance in what we are trying to send back to Twilio. With this being said we don’t have to worry about stringing together Xml string(s) in our code, the TwilioReponse object has a handy property named Element (twilioResponse.Element) that handles nice serialization for us, and provding a representation of of the object in Xml that is Twilio ready for us to send back.

    public class WeatherController : ApiController
    {
        public HttpResponseMessage GatherZipCode(TwilioRequest twilioRequest)
        {
            var twilioResponse = new TwilioResponse();

            twilioResponse.BeginGather(
                new
                {
                    action = "http://myapp.com/api/Weather/RetrieveWeather.xml",
                    finishOnKey = "#"
                });

            twilioResponse.Say(
                "Please enter the zip code of the area you would like the weather in.",
                new {voice = "woman"});

            twilioResponse.EndGather();

            return Request.CreateResponse(HttpStatusCode.OK, twilioResponse.Element);
        }

        public HttpResponseMessage RetrieveWeather(TwilioRequest twilioRequest)
        {
            var zipcode = twilioRequest.Digits;

            var zipWeather = new Dictionary<string, string>
                {
                    {"75042", "sunny"},
                    {"75043", "rainy"},
                    {"75044", "windy"},
                    {"75045", "thunder storms"}
                };

            var twilioResponse = new TwilioResponse();

            twilioResponse.Say(
                string.Format(
                    "The weather conditions in your zip code is {0}",
                    zipWeather[zipcode]), new {voice = "woman"});

            return Request.CreateResponse(HttpStatusCode.OK, twilioResponse.Element);
        }
    }

Great, now how can we do some level of testing with our Twilio ready WebApi’s locally? Meaning let’s do some level of testing before we involve actual people and their actual phones and/or Skype accounts.

You will need to download the Curl utility (http://curl.haxx.se/download.html).

Run your application, and issue a couple of command to invoke your new WebApi methods and make sure they are returning the correct Xml payloads to Twilio, you can cross reference your Xml payloads with Twilio TwiML Referenence (http://www.twilio.com/docs/api/twiml).

Go ahead and spin up command prompt and navigate to the Curl command line utility, now let’s run a couple of commands to inspect the Xml payloads we are expecting to return to Twilio.

curl http://localhost:64190/api/weather/gatherzipcode.xml -X POST

Now when we execute this command we get:

<Response><Gather action="http://myapp.com/api/Weather/RetrieveWeather.xml" finishOnKey="#"><Say voice="woman">Please en
ter the zip code of the area you would like the weather in.</Say></Gather></Response>

Now we can cross reference and compare it with when reviewing the “Say” verb from Twilio TwiML docs on how to use the “Say” verb (http://www.twilio.com/docs/api/twiml/say) to get some level of comfort that we are returning the right Xml payloads from our WebApi methods before actually getting people and phones in the picture.

The next step, if your developing locally, and if you are developing on a workstation that is not publicy exposed to the internet, an option for you could be leveraging Windows Azure Service Bus for it’s relaying features. The Windows Azure Service Bus relaying pattern is pretty much the same pattern used for services that are in cloud that need to work with services that are on-premise that are deep inside a company’s infrastructure behind their firewall.

You can visit Devin’s blog http://www.twilio.com/blog/2012/06/relaying-twilio-requests-using-windows-azure.html to set up relaying with Windows Azure Service Bus for Twilio development.