(For those who’d rather just download the code, the link is at the end.)
Lately I’ve been delving into the ASP.NET MVC framework, the timing of which has been interesting as I am about to finish reading RESTful Web Services by Leonard Richardson and Sam Ruby. It’s an excellent book that I’d highly recommend to anybody designing and creating services for the web, or just interested in it.
This quote from the book description on Amazon.com succinctly describes what’s been floating around in my head for a while:
You’ve built web sites that can be used by humans. But can you also build web sites that are usable by machines? That’s where the future lies, and that’s what RESTful Web Services shows you how to do.
[Emphasis mine]
Why do we have to build web "sites" for humans and different web services for machines? I can create an ASP.NET site, a SOAP-based ASMX web service, or a SOAP or REST (with .NET 3.5) WCF service and while they can share business logic, there’s still a lot of "endpoint code" (for lack of a better term) that has to be implemented, and if I want a human friendly front end + a web API, I have to build a site that essentially wraps another service, since the site itself really is a service.
With the ASP.NET MVC Framework, though, I see the opportunity to unify services and "sites" (human-readable services). Imagine visiting http://www.example.com/books/ and being able to receive back HTML, POX, or JSON, depending on what you asked for–with no additional code required outside of following a convention or two. Web browsers ask for HTML, returning a human consumable page that gets rendered. AJAX or custom clients can request JSON or XML, whatever they know how to interpret best.
The separation of concerns and extensibility that the ASP.NET MVC framework exposes lets us accomplish this with surprisingly little code. At least for read-only services (which is as far as I took it for now.) If you’re not familiar with how the ASP.NET MVC framework works, check out Eilon’s excellent ASP.NET MVC design philosophy post (he also includes many good reference links).
Approach
Outside of the ASP.NET MVC framework itself, from an HTTP perspective I simply want to alter my response format depending on what the incoming request asked for. I decided to keep it simple and only support the "text/html", "application/xml", and "application/json" media types.
I started off trying to use the "Accept" HTTP header as an indicator for what response format the client preferred. After all, that’s what the Accept header is for: "The Accept request-header field can be used to specify certain media types which are acceptable for the response." But I quickly ran into a snafu when I found that Firefox prefers XML over HTML.
That means that every request Firefox makes would result in the uber-friendly XML view.
And because of that snafu, I read up some more on the Accept header - namely what they had to say about it in an appendix of RESTful Web Services:
Hiding this information inside the HTTP headers is a good idea for web browsers, but it shouldn’t be the only solution for web service clients. I recommend exposing different representations using different URIs. … If you want to support Accept on top of this, that’s great (Rails does this too).
There was also some pragmatic advice in the chapter on Representations.
It’s RESTful to keep this information [file format types] in the HTTP headers, and it’s RESTful to put it in the URI. I recommend keeping as much of this information as possible in the URI, and as little as possible in request metadata. I think URIs are more useful than metadata. URIs get passed around from person to person, and from program to program. The request metadata almost always gets lost in translation.
I tend to agree with that. To make it easy and somewhat intuitive, I chose to base the response format on the existence of a querystring parameter named "format". It can specify "xml" or "json", for example http://www.example.com/books/?format=json. But really, you can use any method you want to allow format specification.
Implementation
Formatting the response is the responsibility of the View in the MVC architecture. Since processing requests for HTML content didn’t need to change from the default ASP.NET MVC behavior, all I need to do is override the default WebFormViewFactory functionality and return my own "SerializedView" if the URI indicated xml or json formatting. SerializedView is an abstract base class that encapsulates common functionality and allows sub-classes to perform the serialization, or handle custom error reporting.
When a Controller passes control to a View, it calls the "RenderView" method on the Controller base class, passing in the view name and some optional data - including something called "ViewData" - an object that represents the content the view should render.
Here’s the best part: creating an ASP.NET MVC site+service using my approach means passing a serializable object as ViewData. It’s as simple as that, nothing else needs to change (ok, you need one additional line of code in your Application_Start handler - more on that later). In your ASPX view, you can access the object via ViewData and use all the HTML helpers, UserControls, etc. that you want to build out your HTML, javascript, and who-knows-what.
Unfortunately, the current CTP of the ASP.NET MVC framework does not expose a way to "inject" a different IViewFactory (my subclassed version) into the default Controller created by the ControllerBuilder class. So, that means implementing the IControllerFactory interface and duplicating (ouch!) the code that ControllerBuilder executes, with one somewhat nasty addition.
Yuck! The ViewFactory property is specific to the Controller class, not the IController interface, hence the specific processing — and that also means my approach won’t work for other IController implementations. Not without some extra work, anyway.
This is where the only change you need to make comes in. My IControllerFactory implementation needs to be registered as the default controller factory, which is done in the Application_Start handler - the same place your routes are configured.

Serializable Types
For various reasons, you should use the WCF [DataContract] and [DataMember] attributes to tag your objects as serializable. For one, you gain all the serialization benefits these attributes offer, plus you can use the same contract types across multiple endpoints if you need to. And for another, serializing to JSON via the System.Runtime.Serialization.Json.DataContractJsonSerializer requires the DataContract attribute. If you use the older [Serializable] attribute, you get some interesting results.
The deprecated System.Web.Script.Serialization.JavaScriptSerializer works correctly for objects tagged with [Serializable] but it’s, well, deprecated.
Example
Using the default ASP.NET MVC Application templates, I registered the default ControllerFactory in my Application_Start handler, defined a Books controller with a default action, and a "List" view that prints out some Author and Title information. I also created the following definition of a book.
My controller implementation is no different than it normally would be. I get a list of books and render the "List" view, explicitly specifying the book list as the ViewData. You might notice that I pass the ControllerContext into the GetBooks method. I am experimenting with returning URIs to related resources as part of the data. I’m still playing around, but for now you get my latest attempt.
Requesting the appropriate URI in Firefox yields the expected result from my List view:

And altering the URI returns the appropriate response types, xml or json.

Summary
This ended up being a longer post than I intended, but I hope it was worth it. I’ve put the full source for the "MvcServiceLibrary" and an example up on my Tools page - but here’s the direct download link. I’ll also be checking if this is worth putting into the MvcContrib open source project.
I think that the ASP.NET MVC framework is a huge step forward in creating RESTful web sites, and hopefully now also RESTful web services! Let me know what you think, I love getting feedback.


January 2, 2008 at 05:11
I like this approach, I like alot.
I would only assign the viewfactory in the constructor of the controller (ie in the ConventionController if it’s going to be in the MvcContrib) instead of creating a new controllerfactory.
Anyway, I’ll soon update my sample project at http://www.chrisvandesteeg.nl/2007/12/19/ajax-and-json-for-aspnet-mvc-with-jquery/
to use this approach instead of using masterpages
January 2, 2008 at 20:48
oh, very nice code… let’s hope this ControllerFactory stuff gets figured out.. would be nice to use with NHaml.
January 4, 2008 at 08:51
That’s a pretty cool idea
I can see it being useful for a lot of scenarios, although oftentimes a human user and a computer is interested in different data as well as different representations of it.
January 4, 2008 at 09:01
Thanks Fredrik,
I’m not sure what you mean, though - if a human and a computer is interested in different data, they should be visiting different URIs, consequently accessing different controllers/actions, or at least passing information that modifies the behavior of a controller or action.
If you’re thinking of the situation where the “human readable” version needs *more* information (like say the web page has multiple pieces of information on it), then that can be accomplished using the “TempData” property on the controller. But fundamentally a URI represents a resource of some kind, so different data should have different URIs.
January 4, 2008 at 10:39
I’m definitley tracking with what your doing Aaron. I’ve read the RESTful Web Services book as well and highly recommend it.
I’m trying to work out something similar to this right now, but I’m trying to figure out how I can incorporate WCF as well. I want to be able to expose metadata to facilitate the computer to computer interaction.
I also enjoy the Simply Restful Routing in the MvcContrib. This helps achieve the uniform interface aspect of Resource Oriented Architecture.
January 14, 2008 at 06:11
Nice post. great to see that Webservices in .NET are not exclusively SOAP based !
January 18, 2008 at 06:18
Finger’s crossed this Web Service ViewFactory idea gets added to MVCContrib. Especially as the likes of jQuery 1.2 are now adding better support for Accept Headers. I suppose are people waiting for a newer CTP with better IViewFactory extensibility?
February 1, 2008 at 11:41
Great article, thanks. I’m about to enter the world of MVC and was hoping there was a way to do this. I’ve done the same thing before with URL Rewriting such that no pages are real, instead the “extension” of the file you’re requesting determines the response (but you can’t use real extensions because IIS
February 1, 2008 at 11:44
OK how silly is it that a less than sign terminates comments?
Anyway, because IIS(lessthan)7 makes it so hard to map wildcard extensions into ASP.NET. My URL structure was /whatever,js = JSON, /whatever,xml = XML, /whatever = framed (page) HTML, /whatever.html = raw HTML, etc. I wonder if MVC’s url mapping can handle “[ctl]/[action],js” ?
February 5, 2008 at 13:38
Excellent, well detailed post!
I’ve been doing something very similar to this. In your example, does the json or xml formats render just the ViewData? What about rendering a user control to html, and
So I’m thinking that you could do:
/store/books/5?format=json //renders json format of the book
/store/books/5?format=html&partial=true //renders the html fragment of the user control for the book…
/store/books/5?format=xml //renders xml of the book
/store/books/5 or /store/books/5?format=html //default behavior (book detail page + master page)
And then a convention in the controller would be required to call RenderView to the intended format. Anyway this is good stuff, and worth investigating further.
Keep up the good work!
February 5, 2008 at 13:54
Ben-
Yeah, the possibilities are pretty wide open for how you would want it to work. You could absolutely have it render a user control under certain circumstances.
The decision is really around how you want to handle ViewData (i.e. if you used SmartBag, or the default dictionary, or a specific object) and how you want to translate a request into a specific response (i.e. view).
I think, though, that if you define your convention well in a given project, you can keep the “implementation details” largely out of the controller and inside the plumbing.
Thanks!
February 20, 2008 at 18:22
Ok, so I’m a little late in finding this post, but it certainly grabbed my attention. My question though, is how much more effort would be required to implement update services in this fashion?
Thanks!
February 28, 2008 at 12:20
What about creating a route like:
[controller]/[action]/[id].[format]
You may need to create another one with just controller/action/format, but then you’d be able to do something more RoR-like and request it with an extension, assuming .NET supports that.
Product/List.xml => controller=Product, action=List, format=xml
March 17, 2008 at 13:56
I would simply create:
public class ServiceFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(FilterExecutingContext filterContext)
{ //serialization staff goes here }
}
and assign that class to a Controller’s method which handles requests to all service urls.