I have moved my active blog over to tumblr. I've maintained this blog for reference but will be posting to http://www.robustsoftware.co.uk instead. I've pointed my Feedburner feed to tumblr so if you're subscribed already you should already have switched with me.

RESTful ASP.NET MVC

This is the first in what could be a series of posts on how to modify the internals of ASP.NET MVC in order to make it work in a more RESTful manner. If you want to work with a RESTful web framework built on .NET today then I recommend using OpenRasta.

The reason I’m doing this is two-fold:

  1. I want to learn more about REST beyond the theory and I learn more by doing.
  2. Sometimes it’s impossible to convince people to use an open source framework like OpenRasta, but customising stuff produced by Microsoft is much better received. I hope this will help other people write more RESTful sites whilst using Microsoft-based frameworks.

All the code I will be referring to is available on the restful-aspmvc project page. At the time of writing this the code was on revision 3, so if you are reading this later on there my be some inconsistencies.

The inspiration

I wanted to be able to use RESTful URLs like those available in Ruby on Rails. These work by selecting the controller action through the use of the URL and the HTTP verb.

GET /users/               UsersController.Index()
POST /users/              UsersController.Create()
GET /users/{id}           UsersController.Show(id)
PUT /users/{id}           UsersController.Update(id)
DELETE /users/{id}        UsersController.Destroy(id)

I then wanted to allow you to create different views of the resources by specifying other actions that can only use the GET verb like so:

GET /users/{action}       UsersController.{Action}()
GET /users/{id}/{action}  UsersController.{Action}(id)

The implementation

The above routes are achieved through these route mappings: listing on Google code

The next problem was to map to the different actions according to the URL and the HTTP verb. As web browsers only support GET and POST this requires a technique known as overloading POST. I tried doing this in a couple of ways, firstly by including the required HTTP verb in the URL:

/users/{id}?verb=DELETE

However, I found this quite ugly. As we are overloading POST, there will always be a form involved, therefore I’ve specified the required verb (where necessary) with a hidden form field:

<form method="post" action="/Users/2">
<input value="DELETE" type="hidden" name="_verb" />
<p>
<input value="Delete" type="submit" />
</p>
</form>

Now the verb is specified in the form, we have our URLs working we now need to act on this information. For that I have used a customer controller factory (Google code listing).

There’s a fair bit of code to include directly into a blog post so I’ll explain the general flow to you and if you’re interested in the implementation you can have a look at the listing.

  1. When the controller is created we use the default implementation to retrieve the controller and give it a custom action invoker to use.
  2. When the action is invoked we first check if the verb being used is a POST, if it is we check the form for an override. If one exists we change what we think the HTTP verb is to the one passed.
  3. If no specific action has been used (the default action is Index because of the routes we specified) then we use the HTTP verb and whether an id was specified to determine the actual action required.
  4. We use the default implementation to invoke the action required.

The full code listing includes a basic site which shows all the overrides being used along with a couple of common custom views (new and edit are commonly used to display forms to create and update resources).

This is the first step towards making ASP.NET MVC more RESTful. I welcome your comments and feedback, especially if there is something in particular you’d like me to implement in the future.