Writing an API Controller

Web API ships with MVC, and both utilize controllers. However, Web API does not share the Model-View-Controller design of MVC. They both share the notion of mapping HTTP requests to controller actions, but rather than MVC's pattern of using an output template and view engine to render a result, Web API directly renders the resulting model object as the response. Many of the design differences between Web API and MVC controllers come from this core difference between the two frameworks. This section illustrates the basics of writing a Web API controller and actions.

Examining the Sample ValuesController

Listing 11-1 contains the ValuesController that you get when you create a new project using the Web API project template. The first difference you'll notice is that there is a new base class used for all API controllers: ApiController.

Listing 11.1: ValuesControllers

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace WebApiSample.Controllers
{
    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([FromBody] string value) {
        }
        // PUT api/values/5
        public void Put(int id, [FromBody] string value) {
        }
        // DELETE api/values/5
        public void Delete(int id) {
        }
    }
}

The second thing you'll notice is that the methods in the controller return raw objects rather than views (or other action helper objects). Instead of returning views composed of HTML, the objects that API controllers return are transformed into the best matched format that the request asked for. (We'll talk a little later on about how that process takes place.)

The third difference owes to conventional dispatching differences between MVC and Web API. Whereas MVC controllers always dispatch to actions by name, Web API controllers by default dispatch to actions by HTTP verb. Although you can use verb override attributes like [HttpGet] or [HttpPost], most of your verb-based actions will probably follow the pattern of starting the action name with the verb name. The action methods in the sample controller are named directly after the verb, but they could also have just started with the verb name (meaning Get and GetValues are both reachable with the GET verb).

It's also worth noting that ApiController is defined in the namespace System.Web.Http and not in System.Web.Mvc where Controller is defined. When we discuss self-hosting later, the reason for this will be clearer.

Note
The System.Net.Http library, introduced in .NET 4.5, is an extremely lightweight and type-safe wrapper for both HTTP client and HTTP server applications. The Web API team chose to use this new abstraction to represent requests and responses because it isn't tied directly to the underlying host (whether that's ASP.NET or WCF, the two built-in hosts for Web API).
If MVC 4 and Web API only require .NET 4, how can we use the System.Net.Http library from .NET 4.5? The Web API team got permission to back-port this new library into a form compatible with .NET 4, and ships a binary copy of that library along with MVC 4 (and on NuGet) so that Web API applications can use it while still targeting .NET 4.
We will dicuss System.Net.Http in more detail later in the chapter when convering the implementation differences as well as topic of slef-hosting.

Async by Design: IHttpController

Listing 11-2 shows the interface of ApiController. If we compare this to the interface of MVC's Controller class, we will see that some concepts are the same (controller context, ModelState, Url helper class, User), some are similar but different (Request is HttpRequestMessage from System.Net.Http rather than HttpRequestBase from System.Web), and some are missing (most notably Response and the ActionResult-generating methods).

Listing 11.2: ApiController public interface

namespace System.Web.Http {
    public abstract class ApiController : IHttpController, IDisposable {
        public HttpConfiguration Configuration { get; set; }
        public HttpControllerContext ControllerContext { get; set; }
        public ModelStateDictionary ModelState { get; }
        public HttpRequestMessage Request { get; set; }
        public UrlHelper Url { get; set; }
        public IPrincipal User { get; }

        public virtual Task<HttpResponseMessage> ExecuteAsync(
            HttpControllerContext controllerContext,
            CancellationToken cancellationToken);

        protected virtual void Initialize(
            HttpControllerContext controllerContext);
    }
}

The ExecuteAsync method on ApiController comes from IHttpController, and as you'd expect by its name, it means that all Web API controllers are asynchronous by design. There is no need for a separate class for sync vs. async actions when using Web API. It's also clear that the pipeline here is quite different from ASP.NET, because rather than having access to a Response object, API controllers are expected to return a response object of type HttpResponseMessage.

The HttpRequestMessage and HttpResponseMessage classes form the basis of the HTTP support in System.Net.Http. The design of these classes is quite different from ASP.NET's core runtime classes in that handlers in this stack are given a request message and expected to return a response message. Unlike in ASP.NET, the System.Net.Http classes have no static methods for getting access to information about the ongoing request. This also means that rather than writing directly to a response stream, the developer instead returns back an object which describes the response (and can later render it when needed).

Incoming Action Parameters

To accept incoming values from the request, you can put parameters on your action, and just like MVC, the Web API framework will automatically provide values for those action parameters. Unlike MVC, there is a strong line drawn between values from the HTTP body and values taken from other places (like from the URI).

By default, Web API will assume that parameters which are simple types (that is, the intrinsic types, strings, dates, times, and anything with a type converter from strings) are taken from non-body values, and complex types (everything else) are taken from the body. There is an additional restriction as well: Only a single value can come from the body, and that value must represent the entirety of the body.

Incoming parameters which are not part of the body are handled by a model binding system that is similar to the one included in MVC. Incoming and outgoing bodies, on the other hand, are handled by a brand new concept called formatters. Both model binding and formatters are covered in more detail later in this chapter.

Action Return Values, Errors, and Asynchrony

Web API controllers send values back to the client by way of the return value of the action. As you probably guessed by the signature of ExecuteAsync, actions in Web API can return HttpResponseMessage to represent the response to send back to the client. In some ways, this is similar to the ActionResult return type in MVC. However, returning a response object is a fairly low-level operation, so Web API controllers almost always return a raw object value (or sequence of values) instead.

When an action returns a raw object, Web API will automatically convert it into a structured response in the desired format (like JSON or XML) using a feature of Web API called Content Negotiation. As mentioned earlier, the extensible formatting mechanism which does this conversion will be covered later in the chapter.

This ability to return a raw object is very powerful, but we've lost something with the shift away from ActionResult; namely, the ability to return different values for success and failure. When the signature of your action is strongly tied to the type of the return value that you want to use for success, how can you easily support returning some different representation for errors? If we change the signature of the action to HttpResponseMessage, it complicates the controller action (and unit testing).

To solve this dilemma, Web API allows developers to throw HttpResponseException from their actions to indicate that they are returning an HttpResponseMessage rather than successful object data. In this way, actions which have errors can formulate a new response and throw the response exception, and the Web API framework will treat it as though the action directly returned that response message. Successful responses, then, can continue to return their raw object data and gain the benefits of simpler unit testing.

A final note about action return values: if your action is asynchronous in nature (that is, it consumes other asynchronous APIs), you can modify the signature of your action return value to be Task<T> and use the async and await features in .NET 4.5 to seamlessly convert your sequential code into asynchronous code. Web API understands when actions return Task<T> that it should simply wait for the task to be complete, and then unwrap the returning object of type T and treat it as though the action had returned that directly.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset