Showing posts with label ApiController. Show all posts
Showing posts with label ApiController. Show all posts

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.

Wednesday, December 11, 2013

ASP.NET Web API 2 Content Negotiation & Media Type Formatting

ASP.NET Web API supports requests using HTTP methods. These requests can use any HTTP method including (but not limited to) GET and POST methods. The data to / from the service can use any media type as long as the service is supporting those formats. The client requests can specify the media type format using Accepts or Content-Type details of HTTP message. In the previous posts we discussed how ASP.NET Web API uses content negotiation to provide data to clients based on the requested format. There are some default media type formatters in ASP.NET Web API 2.

All of these MediaTypeFormatter(s) are available in System.Net.Http.Formatting assembly except ODataMediaTypeFormatter, which is available in System.Web.Http.OData assembly. All of them inherit from MediaTypeFormatter abstract base type.



MediaTypeFormatter has two abstract members. These methods are used to determine if a particular type can be formatted using the particular formatter. The methods return true if they support so. Here CanReadType is used when the service receives a request with content type as passed in the argument. On the other hand, CanWriteType is used when some data is to be pushed to client. Again the argument would refer to the data type of the object being pushed to the client.



Here the Read and Write methods in MediaTypeFormatter are asynchronous. BufferedMediaTypeFormatter provides a synchronous wrapper around these methods.

Pipe Delimited Formatter
Let's assume that our service needs to supports providing and accepting students' data in pipe delimited format. Now we need to add support to understand how to parse Student's data when provided by a client. We also need to convert the data pushed to our clients into pipe delimited format. ASP.NET Web API supports formatting data using MediaTypeFormatters. There are two such formatters added by default. They are to support XML and JSON data. If we are planning to support a new format, we need to add an explicit MediaTypeFormatter for such purpose. Here is a simpleton formatter to support pipe delimited data.


As you can notice from the above definition, the same formatter is used to read and write data by the service. Each formatter can be used to support a number of media types. They are identified through SupportedMediaTypes collection in MediaTypeFormatter. Our formatter is supposed to support pipe delimited text data, so the supported media type is specified as "text/pdv".

We must know that the same formatter is used both for reading and writing data by our service. The decision for supported types can be done in CanReadType / CanWriteType method pair. They are from the perspective of our service. Here CanReadType will be used for GET based requests when we need to push data to clients. On the other hand CanWriteType is used when service accepts some data from a client. In order for actual reading and writing of data for these types ReadFromStream and WriteToStream methods are used respectively.

Now we need to add the custom formatter to the list of Media Type Formatters used by the service. This is part of HttpConfiguration for the service. We can update WebApiConfig as follows:



Requesting Data for Configured Media Type Format
In the earlier posts we have seen how we can use Fiddler to request Web API to provide data in the format of the specified media type. We just need to use Accepts header. Here we are specifying the media type as "text/pdv".



Posting Data in Configured Media Type Format
Since our MediaTypeFormatter supports reading Student data in text/pdv format, we can post data to the service in this format. Let us add an action in our InstituteController. The action supports POST method of HTTP. Since we are using Attribute routing, we need to specify the route on the action.


We can compose the request using Fiddler. Here we are posting student's data in Pipe delimited format to the service.



Based on the content type specified in the request, the service picks up the correct MediaTypeFormatter. Since we are supporting data for Student type, the provided data is parsed into Student type format using ReadFromStream method of the formatter. The parsed object is then passed to the requested action as follows:



Download