Barbarian Meets Coding
barbarianmeetscoding

WebDev, UX & a Pinch of Fantasy

5 minutes readwebdev

ASP.NET MVC 4 Wiki - Web API

ASP.NET Web API allows you to easily build RESTful services that embrace the HTTP protocol (in opposition to SOAP and WCF). It’s main advantages are being lightweight and highly interoperable.

You can start using ASP.NET Web API by creating a new web project or installing the self hosted version of Web API via NuGet. Conceptually, it is very similar to ASP.NET MVC but instead of producing HTML views it can produce any media type. Web API can run anywhere, you can run it on IIS or self-hosted.

Routing in Web API

Like ASP.NET MVC, Web API uses controllers to handle web requests. In the case of Web API all our controllers will inherit from ApiController and will contain a series of Action(HTTP) methods: Get, Post, Put, Delete that will reflect the HTTP verbs. The routing will work a little bit differently to ASP.NET MVC, in the sense that, the HTTP verb used when sending and HTTP request to our service will be used to route that request to the corresponding method in the controller.

The RouteConfig for an ASP.NET MVC 4 project with Web API will contain the bits of code below:

// this changes in Web Api 2
// but is a nice illustrative example of routing
routes.MapHttpRoute(
    name: "DefaultApi",
    url: "api/{controller}/{id}",
    defaults: new { id = UrlParameter.Optional }
);

Web API uses convention over configuration when looking for the right method to route your web request to. For instance, in the case of a GET request, Web API will look for a method that starts with Get and matches the expected signature (IEnumerable<Talks> Get())

If you are hosting Web API in IIS, you will need to allow for other HTTP verbs than GET and POST. Verbs such as DELETE, PUT, PATCH, etc are disabled by default.

Content Negotiation

A core concept of HTTP and the Web is content negotiation. Content negotiation consists on a negotiation between client and server to request/serve an specific representation of a resource.

For instance, image that your RESTful API provides access to employee resources and may support different representations of these resources such as images, json, xml, etc. When doing a request an image representation for the resource identified by this URL: api/employees/3 a client will use the HTTP Accept header to specify the MIME type image/png. The server will then be able to serve that image representation for that particular employee.

Web API allows you to manage content negotiation via formatters. You can access the supported formatters via the GlobalConfiguration.Configuration.Formatters in any ApiController. The job of these formatters is to take any object and parse it into a representation in a particular media type. For instance, the JsonMediaTypeFormatter creates a JSON representation of your objects. If the client request a media type that it is not supported by the server, the server will return a default representation, like JSON.

Parameter Binding

Parameter binding in Web API is a little bit different than the one we are used to in ASP.NET MVC. We have seen that content negotiation and formatters impact how data is returned to the client, there’s no ActionResult nor ViewResult nor JSONResult, but parameter binding also differs when binding data as arguments to the action methods.

  • Primitive types: By default they will be bound from the request URL and not from the body. If we want to bind from the body of the request we will need to explicitely specify it with the attribute [FromBody]
public void Post([FromBody]string name)
{
    //...
}
  • Complex Types: They are assumed to be in the message body. Only a single model is allowed to be bound from the message body.

Resolving API urls in Razor

In order to resolve API urls from razor you can use the Url.RouteUrl helper method:

var apiUrl '@Url.RouteUrl("DefaultApi", new { httpRoute="", controller="employees"}'

Sending HTTP Responses to the Client

In order to send HTTP responses to the client Web API provides the HttpResponseMessage type and the Request.CreateResponse helper method to craft http responses:

// 404 not found
return Request.Response(HttpStatusCode.NotFound);

// 200 ok
return Request.Response(HttpStatusCode.OK);

// 200 ok and return representation
return Request.Response(HttpStatusCode.OK, employee);

// 400 bad request
return Request.Response(HttpStatusCode.BadRequest);

// 201 created
var response = Request.CreateResponse(HttpStatusCode.Created, employee);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new {id = employe.Id}));
return response;

Another option when sending error responses to the client is to throw a HttpResponseException exception that also provides functionality for manipulating the HTTP response:

public Employee GetEmployee(int id)
{
    var employee = db.Employees.Find(id);
    if (employee == null)
        throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
    return employee;
}

Testing Web API Services

A couple of interesting tools you can use to test your web api services are cURL and fiddler.

> cURL http://localhost:1111/api/talks
> cURL http://localhost:1111/api/talks -X GET
> cURL http://localhost:1111/api/talks/5 -X GET

> cURL http://localhost:1111/api/talks/5 -X DELETE

> cURL http://localhost:1111/api/talks -X GET -v # verbose
> cURL http://localhost:1111/api/talks -X GET -v -H "Accept: application/json"

> cURL http://localhost:1111/api/talks -X POST -d "name=john&surname=doe"

Consuming an ASP.NET MVC Web API

ASP.NET Web API also ships with a client library WebApi.Client that eases you to consume services over HTTP:

var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));

var result = await client.GetAsync(uri).Result;

if (result.StatusCode == HttpStatusCode.OK)
{
    var content = await result.Content.ReadAsStreamAsync().Result;
    var doc = XDocument.Load(content);
    // ...
}

References


Jaime González García

Written by Jaime González García , dad, husband, software engineer, ux designer, amateur pixel artist, tinkerer and master of the arcane arts. You can also find him on Twitter jabbering about random stuff.Jaime González García