Using IHttpActionResult with WebAPI2

This is another post relating to the new features in WebApi2.

When you start a new WebAPI controller, the template used is


public IEnumerable<string> Get()
{
    return new string[] { "value1", "value2" };
}

// POST api/<controller>
public void Post([FromBody]string value)
{
}

// PUT api/<controller>/5
 public void Put(int id, [FromBody]string value)
 {
 }

Once you start working with the WebAPI, you soon realize that this is not enough, as you need to return status information as well, so eventually you progress to using HttpResponseMessage as the return type for all calls. When using HttpResponseMessage, to send the response from an API, you typically use one of two methods:

  • Request.CreateResponse()
  • Request.CreateErrorResponse()

With each method, you can pass in an HttpStatusCode to get more fine grained control of what status code to be returned.  There is a third method, but its only used for OData.

With WebAPI2, IHttpActionResult interface has been introduced. The definition from MSDN is “Defines a command that asynchronously creates an HttpResponseMessage.”

It is now recommended to use IHttpActionResult instead of HttpResponseMessage for all WebAPI responses. To help with this, there are several common Methods to create responses:

  • Ok()
  • Ok<T>(T)
  • BadRequest()
  • NotFound()

A full list can be found here:

With the following method,

[ResponseType(typeof(Policy))]
public HttpResponseMessage Get(int id)
{
    var policyToReturn = _policyRepository.GetPolicyFor(id);
    if ( policyToReturn == null )
        return Request.CreateResponse(HttpStatusCode.NotFound);
    var response = Request.CreateResponse(HttpStatusCode.OK,
        policyToReturn);
    return response;
}

Using IHttpActionResult, is the Get method is now

[ResponseType(typeof(Policy))]
public IHttpActionResult Get(int id)
{
    var policyToReturn = _policyRepository.GetPolicyFor(id);
    if (policyToReturn == null)
        return NotFound();
    return Ok(policyToReturn);
}

Just comparing the before and after result of the change, the code looks cleaner. However, after changing the code, the test project will no longer compile. The following test will not compile

[Test]
public void When_Call_Get_Then_Expected_Data_Is_Returned()
{
    IList<Policy> mockDatabase = GetMockDatabase();
    _mockPolicyRepository.Setup(m => m.Get())
        .Returns(mockDatabase);
    var controller = GetControllerForTests();
    var response = controller.Get();
    Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
    var returnedObjects = response.Content.
        ReadAsStringAsync().Result;
    var returnedListOfPolicy = (List<Policy>)JsonConvert.
        DeserializeObject(returnedObjects, typeof(List<Policy>));
    Assert.That(returnedListOfPolicy.Count,
        Is.EqualTo(mockDatabase.ToList().Count));
}

With the following errors:

  • ‘System.Web.Http.IHttpActionResult’ does not contain a definition for ‘StatusCode’ and no extension method ‘StatusCode’ accepting a first argument of type ‘System.Web.Http.IHttpActionResult’ could be found (are you missing a using directive or an assembly reference?) C:\MyProjects\MotorDB\MotorDB.UI.Tests\ApiControllerTests\PolicyControllerTests.cs
  • ‘System.Web.Http.IHttpActionResult’ does not contain a definition for ‘Content’ and no extension method ‘Content’ accepting a first argument of type ‘System.Web.Http.IHttpActionResult’ could be found (are you missing a using directive or an assembly reference?) C:\MyProjects\MotorDB\MotorDB.UI.Tests\ApiControllerTests\PolicyControllerTests.cs

As with clearning up the controller code, unit testing is also made easier. The above test is now

[Test]
public void When_Call_Get_Then_Expected_Data_Is_Returned()
{
    IList<Policy> mockDatabase = GetMockDatabase();
    _mockPolicyRepository.Setup(m => m.Get())
        .Returns(mockDatabase);
    var controller = GetControllerForTests();
    var response = controller.Get();
    var returnedListOfPolicy =
        response as OkNegotiatedContentResult<IList<Policy>>;
    Assert.That(returnedListOfPolicy, Is.Not.Null);
    Assert.That(returnedListOfPolicy.Content.Count,
        Is.EqualTo(mockDatabase.Count()));
}

No more conversion of data, The OkNegotiatedContentResult does that for us.

The only thing that have not yet discovered what to do is to check the StatusCode like used to be able to. If you debug the unit test, and stop after the Get method, and inspect the response object, there is nothing to indicate the StatusCode of Get methods. Not yet worked on PUT or POST methods, those will be the topic of another post

Advertisement
About

My musing about anything and everything

Tagged with: ,
Posted in TDD, WebAPI
One comment on “Using IHttpActionResult with WebAPI2
  1. TS says:

    Status is implicit. Since you use OkNegotiatedContentResult and check that it isn’t null, you know that the status is an OK status (200)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 13 other subscribers
%d bloggers like this: