ASP.NET MVC 4 Web API Routes and ApiController

ASP.NET MVC 4 Web API Routes and ApiController

This is the 3rd post in a series of ASP.NET MVC 4 Tutorials. The first two posts were on ASP.NET MVC 4 Bundling and Minification and ASP.NET MVC 4 Entity Framework and Data Migrations. In this tutorial I want to briefly look at the new Web API integration in ASP.NET MVC 4. Web API introduces a new route for API calls as well as an ApiController that responds to Get, Post, Put, and Delete requests from REST Clients. Web API introduces formatters that can do content negotiation via XML, JSON, etc. as well as provides better customization of the response using HttpResponseMessage.

ASP.NET MVC 4 Web API Project

ASP.NET MVC 4 introduces several new project types after you initially pick that you want to develop an ASP.NET MVC 4 Web Application. One of those application types is the new Web API Project.

ASP.NET MVC 4 Web API Project

If you choose the Web API Project, a new Web API Controller Class is created for you to provide an example of responding to Get, Post, Put, and Delete requests for your API.

public class ValuesController : ApiController {

   // GET /api/values
    public IEnumerable<string> Get() {
        return new string[] { "value1", "value2" };
    }

    // GET /api/values/5
    public string Get(int id) {
        return "value";
    }

    // POST /api/values
    public void Post(string value) {}

    // PUT /api/values/5
    public void Put(int id, string value) {}

    // DELETE /api/values/5
    public void Delete(int id) {}
}

With the Web API Project you will also notice a new API specific route added to the RouteTable in Global.asax.cs.

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

Running the project and navigating to ~/api/values will display a list of the values in XML Format. I removed the XML namespacing to keep things simple.

<ArrayOfString>
    <string>value1</string>
    <string>value2</string>
</ArrayOfString>

If you change the Accept Header so that you will only accept JSON, the same controller action will send the values via JSON instead.

["value1","value2"]

Web API Controller Class - ApiController in ASP.NET MVC 4

Creating a new Web API Controller Class is as simple as using the Add Controller Recipe in ASP.NET MVC 4 and choosing the Empty API controller Tempate

Web API Controller Class in ASP.NET MVC 4

Or, you could just create one via Add Item which has a new Web API Controller Class as an option.

I created a simple ProductsController that handles all the CRUD options for products in a mythical e-commerce website.

public class ProductsController : ApiController {
    private readonly IRepository<Product> _repository;

    public ProductsController(IRepository<Product> repository) {
        _repository = repository;
    }

    public IEnumerable<Product> Get() {
        return _repository.Queryable();
    }

    public Product Get(int id) {
        var product = _repository.Get(id);

        if (product == null)
            throw new HttpResponseException(HttpStatusCode.NotFound);

        return product;
    }

    public HttpResponseMessage<Product> Post(Product product) {
        _repository.Add(product);

        var response = new HttpResponseMessage<Product>
(product, HttpStatusCode.Created);
        response.Headers.Location = new Uri(Request.RequestUri,
Url.Route(null, new {id = product.Id}));

        return response;
    }

    public Product Put(int id, Product product) {
        var existingProduct = _repository.Get(id);

        if (existingProduct == null)
            throw new HttpResponseException(HttpStatusCode.NotFound);

        _repository.Save(product);

        return product;
    }

    public HttpResponseMessage Delete(int id) {
        _repository.Delete(id);

        return new HttpResponseMessage(HttpStatusCode.NoContent);
    }
}

You can see that in some instances I am just returning a Product and in other instances I am returning a more informational HttpResponseMessage. For example, in the case of the Post of a new Product, I need to tell the REST Client the new location of the newly added product in the header. In other actions I am also throwing a HttpResponseException if the resource requested is not found. Validation, Logging, and other concerns are being done in various ActionFilters just like in your normal ASP.NET MVC Projects. Try to pull those cross-cutting concerns out of the main logic as much as possible.

ASP.NET Web API OData Syntax for Paging and Querying

If you want to enable various paging and querying of products you can make a slight change to the Get ApiController Action and return an IQueryable<Product> as opposed to IEnumerable<Product>.

public IQueryable<Product> Get() {
    return _repository.Queryable();
}

Now from your browser you can add paging, filtering, sorting, and other options to shape the data. Here is an example call that does paging and sorting.

api/products?$skip=2&$top=2&$orderby=Title

The XML Response by the browser is:

<ArrayOfProduct>
    <Product>
        <Id>3</Id>
        <Title>RipStik</Title>
        <Price>69.00</Price>
    </Product>
    <Product>
        <Id>4</Id>
        <Title>Shred Sled</Title>
        <Price>49.00</Price>
    </Product>
</ArrayOfProduct>

Or the JSON Response:

[{"Id":3,"Price":69.00,"Title":"RipStik"},
{"Id":4,"Price":49.00,"Title":"Shred Sled"}]

Conclusion

ASP.NET Web API integration with ASP.NET MVC 4 is really slick. Now you can easily create an API for your website using the new ApiController Base Class to respond to REST Clients.

Make sure you check out my other ASP.NET MVC 4 Tutorials.