How can ASP. NET Web APIs convert the return values of controller actions to HTTP response messages?
Preface
This topic describes how ASP. NET Web APIs convert the return values of controller actions to HTTP response messages.
The Web API controller action can return any of the following values:
1, void
2. HttpResponseMessage
3. IHttpActionResult
4, Some other type
Depending on which one is returned, the Web API uses different mechanisms to create an HTTP response.
Return type |
How Web API creates the response |
Void |
Return empty 204 (No Content) |
HttpResponseMessage |
Convert directly to an HTTP response message. |
IHttpActionResult |
Call ExecuteAsync to create an HttpResponseMessage, then convert to an HTTP response message. |
Other type |
Write the serialized return value into the response body; return 200 (OK ). |
The remainder of this section describes each return value in detail.
Void
If the returned type is type, the Web API returns an empty HTTP response with the status code 204 (No Content.
Example controller:
public class ValuesController : ApiController{ public void Post() { }}
HTTP:
HTTP/1.1 204 No ContentServer: Microsoft-IIS/8.0Date: Mon, 27 Jan 2014 02:13:26 GMT
HttpResponseMessage
If an action returns HttpResponseMessage, Web API constructs a message through the HttpResponseMessage attribute to directly convert the returned value to an HTTP response.
public class ValuesController : ApiController{ public HttpResponseMessage Get() { HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, "value"); response.Content = new StringContent("hello", Encoding.Unicode); response.Headers.CacheControl = new CacheControlHeaderValue() { MaxAge = TimeSpan.FromMinutes(20) }; return response; } }
Correspondingly:
HTTP/1.1 200 OKCache-Control: max-age=1200Content-Length: 10Content-Type: text/plain; charset=utf-16Server: Microsoft-IIS/8.0Date: Mon, 27 Jan 2014 08:53:35 GMThello
If a domain model is passed to the CreateResponse method, the Web API writes the serialization model to the response body using the media formatter.
public HttpResponseMessage Get(){ // Get a list of products from a database. IEnumerable
products = GetProductsFromDB(); // Write the list to the response body. HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, products); return response;}
IHttpActionResult
The IHttpActionResult interface is introduced in Web API 2. Essentially, it defines an HttpResponseMessage factory. The following are the benefits of using the IHttpActionResult interface:
1. Simple unit testing for your Controller
2. Move the public logic to a separate class for the HTTP Creation
3. Build the corresponding underlying details to make the Controller action clearer by hiding them.
IHttpActionResult contains a separate method ExecuteAsync, which asynchronously creates an HttpResponseMessage instance:
public interface IHttpActionResult{ Task
ExecuteAsync(CancellationToken cancellationToken);}
If a controller action returns IHttpActionResult, the Web API calls the ExecuteAsync method to create the HttpResponseMessage. Then, convert HttpResponseMessage to the corresponding HTTP message.
The following is a simple execution of IHttpActionResult, which creates a text:
public class TextResult : IHttpActionResult{ string _value; HttpRequestMessage _request; public TextResult(string value, HttpRequestMessage request) { _value = value; _request = request; } public Task
ExecuteAsync(CancellationToken cancellationToken) { var response = new HttpResponseMessage() { Content = new StringContent(_value), RequestMessage = _request }; return Task.FromResult(response); }}
Controller action example:
public class ValuesController : ApiController{ public IHttpActionResult Get() { return new TextResult("hello", Request); }}
Correspondingly:
HTTP/1.1 200 OKContent-Length: 5Content-Type: text/plain; charset=utf-8Server: Microsoft-IIS/8.0Date: Mon, 27 Jan 2014 08:53:35 GMThello
Generally, you can use the IHttpActionResult defined in the System. Web. Http. Results namespace.
In the following example, if the request does Not match any existing product ID, the Controller will call ApiController. NotFound to create a 404 (Not Found) response. Otherwise, the Controller will call ApiController. OK, which will call a 200 (OK) that contains the product.
public IHttpActionResult Get (int id){ Product product = _repository.Get (id); if (product == null) { return NotFound(); // Returns a NotFoundResult } return Ok(product); // Returns an OkNegotiatedContentResult}
Other Return Types
For all other return types, Web APIs use media formatter to serialize the returned values. The Web API writes serialized values to the response body. The response status code is 200 (OK ).
public class ProductsController : ApiController{ public IEnumerable
Get() { return GetAllProductsFromDB(); }}
The disadvantage of this implementation is that you cannot directly return an error code, such as 404.
The Web API selects the format by using the Accept header in the request.
Sample request:
GET http://localhost/api/products HTTP/1.1User-Agent: FiddlerHost: localhost:24127Accept: application/json
Example:
HTTP/1.1 200 OKContent-Type: application/json; charset=utf-8Server: Microsoft-IIS/8.0Date: Mon, 27 Jan 2014 08:53:35 GMTContent-Length: 56[{"Id":1,"Name":"Yo-yo","Category":"Toys","Price":6.95}]