WebApi controller actions can return a variety of response types: HttpResponseMessage, IHttpActionResult, CLR objects and then the Task based variety of each for async actions. But which one is best? And how do we unit test them? Lets look at each in turn and examine why IHttpActionResult is usually the right choice.
Synchronous controllers returning objects
The simplest web api controller can directly return the object in question. Say you have a ProductController that is concerned with CRUD operations on Products, it might have a method like the below:
public Product Get(int id)
{
return dbContext.Products.Get(id);
}
We have returned the Product type directly making this the simplest solution and in addition it is trivial to unit test the returned values. However with a little complexity this pattern wont work.
Returning a status code if something goes wrong
Just returning our domain objects from the controller fails if we we have to change status codes, messages and/or headers in the response. To make that finer level of control you have to return HttpResponseMessage like so:
public HttpResponseMessage Get(int id)
{
var product = dbContext.Products.Get(id);
if(product == null)
return Request.CreateResponse(HttpStatusCode.NotFound);
// could also throw a HttpResponseException(HttpStatusCode.NotFound)
return Request.CreateResponse(HttpStatusCode.OK, product);
}
As you see we can now manipulate the response, by setting the code in this case. However we have to wrap the response so unit testing this is also more involved. You have to use TryGetContentValue on the response object to read the content of the http message, and you have to initialise the request and configuration properties on the controller. For this reason IHttpActionResult was introduced.
IHttpActionResult is Ok()
WebApi 2 introduced a new interface and some helper methods to make this pattern of constructing responses slightly simpler. Unless you have an old codebase it is better to forget about HttpResponseMessage. ApiController has new methods to generate the responses for you, and there are a set of classes for the most common result types such as OkNegotiatedContentResult.
public IHttpActionResult Get(int id)
{
var product = dbContext.Products.Get(id);
if (product == null)
return NotFound();
return Ok(product);
}
The above looks simpler the the HttpResponseMessage example and hides the lower level http message construction away from your controller.
To unit test this style of return value there we must do some casting and generics to get at the actual products in the response:
var actionResult = controller.Get(123);
var contentResult = actionResult as OkNegotiatedContentResult<Product>;
Assert.IsNotNull(contentResult);
var product = contentResult.Content;
What about an async controller and IHttpActionResult?
If you need to make the controller async then you have to wrap the result in a task and use await, in the same way that you make any other method asynchronous. Remember that if you are doing async, you should use it all the way down and not synchronously block on an async method. We have async controllers for this purpose:
public async Task<IHttpActionResult> GetAsync(int id)
{
var product = await dbContext.Products.GetAsync(id);
if (product == null)
return NotFound();
return Ok(product);
}
Unit testing the async IHttpActionResult web api controller
The approach is to make the test itself async so we can use the await syntax to unwrap the task for us and get at the underlying product content. Here I am using NUnit2, but other frameworks are very similar.
[Test]
public async Task GetProductAsyncReturnsCorrectProduct()
{
var productDbMock = GetMockProductDb();
var controller = new ProuductController(productDbMock);
var result = await controller.GetProductAsync(123) as OkNegotiatedContentResult<Product>;
Assert.IsNotNull(result);
Assert.AreEqual(123, result.Content.Id);
}
So which return type should I choose?
If your controller is trivial then you may be able to get away with returning an object directly but most real world controllers have multiple return paths and require more control over the http response. For that reason I would always recommend using IHttpActionResult as the return type (or its async alternative) for all your API controllers. It is easier to read and test than the http message based return type, and wrapping your responses with Ok()
is not much more effort than returning them directly.