REST for ASP.NET MVC SDK

REST - Representational State Transfer Earlier this week, Phil Haack did a post on the newly released REST for ASP.NET MVC SDK. I had the feeling though that this post did not really get the attention it deserved. I do not have the idea my blog gets more visitors than Phil’s, but I’ll try to give the SDK some more attention by blogging an example. But first things first…

kick it on DotNetKicks.com

What is it?

“REST for ASP .NET MVC is a set of capabilities that enable developers building a website using ASP .NET MVC to easily expose a Web API for the functionality of the site. “

Ok then. Now you know. It will get more clear after reading the next topic.

When should I use this?

There are of course features in WCF that enable you to build REST-ful services, but…

In many cases, the application itself is the only reason for development of the service. In other words, when the only reason for the service’s existence is to service the one application you’re currently building, it may make more sense  would stick with the simple case of using ASP.NET MVC. (Phil Haack)

Quickly put: why bother setting up a true WCF service layer when the only reason for that is the web application you are building?

Let me add another statement. Add a comment if you disagree:

In many cases, you are building an ASP.NET MVC application serving HTML, and building a WCF layer exposing XML and/or JSON using REST, so you can use this in your Ajax calls and such. Why build two or three things displaying the same data, but in another format?

This is where the REST for ASP.NET MVC SDK comes in handy: it adds “discovery” functionality to your ASP.NET MVC application, returning the client the correct data format he requested. From the official documentation:

  1. It includes support for machine-readable formats (XML, JSON) and support for content negotiation, making it easy to add POX APIs to existing MVC controllers with minimal changes.
  2. It includes support for dispatching requests based on the HTTP verb, enabling “resource” controllers that implement the uniform HTTP interface to perform CRUD (Create, Read, Update and Delete) operations on the model.
  3. Provides T4 controller and view templates that make implementing the above scenarios easier.

An example…

… a simple ASP.NET MVC application!

Let’s say you have an application where you can create, read, update and delete your own name and firstname. We have a simple model for that:

[code:c#]

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

[/code]

We can do CRUD operations on this in our ASP.NET MVC application, using the action methods in our PersonController:

[code:c#]

public class PersonController : Controller
{
    protected List<Person> Data
    {
        get
        {
            if (Session["Persons"] == null)
            {
                Session["Persons"] = new List<Person>();
            }
            return (List<Person>)Session["Persons"];
        }
    }

    //
    // GET: /Person/

    public ActionResult Index()
    {
        return View(Data);
    }

    //
    // GET: /Person/Details/5

    public ActionResult Details(int id)
    {
        return View(Data.FirstOrDefault(p => p.Id == id));
    }

    //
    // GET: /Person/Create

    public ActionResult Create()
    {
        return View(new Person());
    }

    //
    // POST: /Person/Create

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Person person)
    {
        try
        {
            person.Id = Data.Count + 1;
            Data.Add(person);

            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

    //
    // GET: /Person/Edit/5

    public ActionResult Edit(int id)
    {
        return View(Data.FirstOrDefault(p => p.Id == id));
    }

    //
    // POST: /Person/Edit/5

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(int id, FormCollection collection)
    {
        try
        {
            Person person = Data.FirstOrDefault(p => p.Id == id);
            UpdateModel(person, new string[] { "FirstName", "LastName" }, collection.ToValueProvider());
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }
}

[/code]

Any questions on this? Read the book :-)

… get some REST for FREE!

Like all “free” things in life, there’s always at least a little catch. “Free” in this case means:

  1. Adding a reference to System.Web.Mvc.Resources.dll provided by the REST for ASP.NET MVC SDK
  2. Registering another controller factory in Global.asax.cs (more on that later)
  3. Adding the [WebApiEnabled] to every controller and/or action method you want to expose via REST.

The first step is quite straightforward: get the bits from CodePlex, compile, and add it as a reference in your MVC project. Next, open Global.asax.cs and add the following in Application_Start:

[code:c#]

protected void Application_Start()
{
    // We use this hook to inject our ResourceControllerActionInvoker
    // which can smartly map HTTP verbs to Actions
    ResourceControllerFactory factory = new ResourceControllerFactory();
    ControllerBuilder.Current.SetControllerFactory(factory);

    // We use this hook to inject the ResourceModelBinder behavior
    // which can de-serialize from xml/json formats
    ModelBinders.Binders.DefaultBinder = new ResourceModelBinder();

    // Regular register routes
    RegisterRoutes(RouteTable.Routes);
}

[/code]

What we do here is tell ASP.NET MVC to create controllers using the ResourceControllerFactory provided by the REST for ASP.NET MVC SDK.

Next: add the [WebApiEnabled] to every controller and/or action method you want to expose via REST. And that’s about it. Here’s what I get in my application if I browse to http://localhost:2681/Person:

image

Nothing fancy here, just a regular ASP.NET MVC application. But wait, let’s now browse to http://localhost:2681/Person?format=Xml:

image

Cool, no? And we only added 4 lines of code. But there’s more! I can also browse to http://localhost:2681/Person?format=Json and get JSON data returned. But that’s not all. There’s more!

  • You can add custom FormatHandler classes and, for example, provide one that handles RSS data.
  • There’s no need to always add the query string variable “format”: you can also specify the type of content you want in your HTTP request, by setting the HTTP “Accept” header. For example, if I set the Accept header to “application/json,text/xml”, REST for ASP.NET MVC will provide me with JSON if possible, and if not, it will send me XML. This approach is particularly useful when working with AJAX calls on your view.

Downloads

Here’s a list of downloads:

kick it on DotNetKicks.com

This is an imported post. It was imported from my old blog using an automated tool and may contain formatting errors and/or broken images.

Leave a Comment

avatar

8 responses

  1. Avatar for Arnis L.
    Arnis L. August 20th, 2009

    Thanks for an example. Didn't check it yet but looks quite promising.

  2. Avatar for Dirk Rodermund
    Dirk Rodermund August 20th, 2009

    Hi Maarten,
    nice post, I didn't had a look at it, but how does this works together with other controller factories? For example, I use the WindsorControllerFactory for dependency injection. Both type of controllers are adding responsibilities to "a factory" with are orthogonal, one care for formatting, the other for dependency injection.
    Is there a way to "chain" the controller factories, so both can do their job?

  3. Avatar for maartenba
    maartenba August 20th, 2009

    THis is a separate controller factory, so Windsor will be a problem at the moment. I had the same "issue" in my mind yesterday, thinking of an elegant way to perform such chaining.

  4. Avatar for Maarten
    Maarten August 21st, 2009

    Dirk, when you first set the WIndsorControllerFactory as the default controlle rfactory and afterwards the REST factory, you should be OK. The REST factory sits on top of the default factory and thus provides chaining over the default factory and itself.

  5. Avatar for Dirk Rodermund
    Dirk Rodermund August 21st, 2009

    Maarten, thanks for pointing me in the right direction! I was not aware that the factories can be chained this way!
    But from my point of view it feels a bit strange to have a controller factory which is not really creating the controller, it only adds behavior to the controller created by the default controller factory. A nicer approach could be to use extension points in the factory to modify the controller after creation. Wouldn't it be a better SoC?

  6. Avatar for Maarten
    Maarten August 21st, 2009

    True, but that's something that is not in the MVC core at the moment...

  7. Avatar for Uzivatel
    Uzivatel August 28th, 2009

    if I set the Accept header to “application/json,text/xml”, REST for ASP.NET MVC will provide me with JSON if possible, and if not, it will send me XML.

    Does it mean it will provide me JSON when I have javascript turned on, and will fall down to xml (xhtml) when I have it switched off?

    If not how can I achieve this thing? i.e. parse JSON data and have AJAX calls, but have ability to get data for clients which do not have javascript turned on. Or at least no AJAX (as this is hard on mobile browser).

    Thanks for clearing what you meant.

  8. Avatar for Maarten
    Maarten August 28th, 2009

    It's more depending on how your Ajax calls (for example) are created. If the library you use wants Json and specifies the correct header it will get Json. Otherwise it will get XML or even plain HTML if no ?format query option or correct header is given.