Saturday, December 14, 2013

ASP.NET Web API 2 - Action's Response and IHttpActionResult

This is a continuation of our discussion about ASP.NET Web API. In this post we are trying to understand how results generated by actions are interpreted and further processed by ASP.NET Web API message pipeline. In the previous posts, we have defined various actions with three different types of returned data. There are following return types you might see for Web API action implementations:
  1. HttpResponseMessage
  2. IHttpActionResult [ASP.NET Web API 2]
  3. Any other type
  4. void
Every ASP.NET Web Api requests passes through a pipeline before a particular controller's action is invoked. The action's response can also be processed and passed through various stages before it is pushed to the requester. This is also possible that all the formatting is done at the action's side generating an HttpResponseMessage, resulting in bypassing all these stages. At the end, irrespective of returned data, an HttpResponseMessage is generated.

ASP.NET Web API message life cycle poster can be obtained from Microsoft's download center. If you understand the flow of message as described in this poster then you understand it all. So make sure that all the particular pieces are looked at with great emphasis and care.

Return type as void
These are the simplest of all actions from development perspective. They are specially useful for the requests with HTTP verbs including PUT / DELETE and POST. In these cases, the client is not interested in the data returned form the service. They are for pushing data to the service. Let's just make sure that having a return type as void doesn't mean nothing is being returned to the client and still an HttpResponseMessage is generated.

Returning Domain Object
This is the simplest and easiest of all options. Here we treat our actions invocations as regular methods calls. We return domain objects from these actions. In this way, our actions' code is not populated with the HTTP based types. It is the framework's responsibility to create an HTTP response including the returned data as value.

It is for these actions, that framework hooks up the injected MediaTypeFormatter (s) and Content Negotiators based on the media types requested by client and type of data being returned. After data is passed through these stages, an HttpResponseMessage is generated and returned to the client.

Returning HttpResponseMessage Directly
This is another option allowed for Web API actions. Here the API takes the responsibility for creating the response on its own making it easier for the framework handling the response message. As a developer, we have the flexibility for controlling the HttpStatusCode generated with the response.

As you can see here, in addition to the data, we are specifying the HttpStatusCode for the returned response. We are using the value OK (= 200).

IHttpActionResult Interface & ASP.NET Web API 2
Here we are neither generating the domain objects directly nor we are handcrafting the HttpResponseMessage directly in ApiController's actions in a synchronous fashion. Instead, we are returning a response held by a type implementing IHttpActionResult interface. ASP.NET Web API 2 introduced IHttpActionResult in order to support asynchronous generation of HttpResponseMessage.

It also introduced a number of implementations of the interface in System.Web.Http.Results namespace in System.Web.Http assembly.

ApiController has also been updated with a number of additional methods returning such results. They make it easier for generating the response. They also include the appropriate HttpStatusCode with the response based on the method being used. These methods are supposed to be used from ApiController's actions to generate a response. The value obtained from these methods can simply be returned by the controller's action method.

The following is an example action supporting HTTP Post method. The action accepts student's data from the request body. After writing the data to the console, it generates an HTTP OK for the requesting client.

Let us see how our service responds to a request invoking the above action. In order to keep the example simple, the action is not doing much other than just writing the student's data to the console. It is also generating an OKResult (implements IHttpActionResult) by calling the Ok() method defined in ApiController type.

We can also provide custom implementation of the interface and use them in Web Api actions.

Returning Errors
The actions with return type as void or any other type other than HttpResponseMessage has only one way to return an error response i.e. to throw an exception in the event. The exception is caught by the framework pipeline and an appropriate error response is generated.

On the other hand the actions returning HttpResponseMessage can always generate error responses. Here we are using Request property of ApiController. This is of type HttpRequestMessage.

If this is a web client, the error is displayed in the browser as follows:

For the actions returning IHttpActionResult, we can always return different implementations of the interface based on the underlying condition. In case of error we may also use the methods added in ApiController for such conditions.

No comments: