ASP.NET Web Api is silly easy

Note: this post is over a year old, it's very likely completely outdated and should probably not be used as reference any more. You have been warned. :-)

... Well: silly easy if you don't have too many requirements, but I did. Good news though: solved my problems in under 2 hours.

What is the ASP.NET Web API? Well, according to Microsoft: "ASP.NET Web API is a framework that makes it easy to build HTTP services that reach a broad range of clients, including browsers and mobile devices. ASP.NET Web API is an ideal platform for building RESTful applications on the .NET Framework."

When I saw the demo at the TechDays last month, I formulated the following explenation: Anything that returns IEnumerable can now be accessed as XML/JSON and anything IQueryable can be queried with OData syntax; very very easily.

Here's what I had to do to go from a MVC3 site that uses Ninject for dependency injection to a MVC4 site that can answer to Web API calls.

First of all, I had to upgrade my solution to MVC4. The asp.net site provides detailed upgrade instructions that just work.

Next, I installed Web API NuGet package into my existing web project. For some reason, the routing was not updated so in my global.asax.cs I had to add the route like so:

routes.MapHttpRoute("Default API Route",
"api/1.0/{controller}/{id}",
new { id = RouteParameter.Optional });

I think it's pretty self-explanatory that any ApiController I will add can be resolved through the URL /api/1.0/MyControllerName.

In the VS11 tooling (I don't know if this works with VS2010) I can now add a new controller of type API controller. If it doesn't work in VS2010, just create a new controller and inherit from ApiController instead of Controller.

2012-03-30_185208

Just running the default code for this worked fine, but of course I wanted to use Web API to access some of my existing database content.

So I added a constructor that accepted a IInfoService class and set up a field for it so it could be injected by Ninject. Well.. *BOOM* that didn't work, error:

The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.

Well, after a bit of Googling the answer was provided by Phil Haack: You need to configure a dependency resolver for Web API. To add to the class he posted there, I had to have these usings in place to make it work (make sure to use System.Web.Http.Services instead of System.Web.Mvc): 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http.Services;

Perfect! Or so I thought.. Now when trying to call into the API, something was wrong with the serialization of my object due to the following error:

The type 'MyType' cannot be serialized to JSON because its IsReference setting is 'True'. The JSON format does not support references because there is no standardized format for representing references. To enable serialization, disable the IsReference setting on the type or an appropriate parent class of the type.

Another round of Googling and I found out that the default Microsof serializer does not support my type of object. Problem is, I can't just change my class either. So in comes my favourite Javascript serializer: Json.NET. Another quick NuGet install and then I had to replace the default MS serializer with Json.NET.

The blog post in the last link is actually missing and important piece for me with my Web Application project (it refers to a self-hosted controller, I'm hosting my controllers in my Application!). So, using the JsonFormatter class, I added the following to my global.asax.cs:

// Create Json.Net formatter serializing DateTime using the ISO 8601 format
var serializerSettings = new JsonSerializerSettings();
serializerSettings.Converters.Add(new IsoDateTimeConverter());
var jsonNetFormatter = new JsonNetFormatter(serializerSettings);
var index = GlobalConfiguration.Configuration.Formatters.IndexOf(GlobalConfiguration.Configuration.Formatters.JsonFormatter);
GlobalConfiguration.Configuration.Formatters.RemoveAt(index);
GlobalConfiguration.Configuration.Formatters.Insert(index, jsonNetFormatter);

And there you have it, now when I run the Web API call I get an actual beautiful JSON object back and if you look at the url, I even did some oData querying, because I could! My Get() function returns an IQueryable, from which you get oData querying automatically, awesome!

2012-03-30_192652

Of course, if you start with a MVC4 project in the future then most of this will be solved for you. I fully expect Ninject to do some updates so that their NuGet package will just make this work. The only thing that you might need to do is use Json.NET sometimes if you have unsupported objects that can't be changed.

Sebastiaan Janssen

Dutch guy living in (and loving) Copenhagen, working at Umbraco HQ. Lifehacker, skeptic, music lover, cyclist, developer.