One of the small things (aka hidden gems) that was released with Web API 2.1, was the support of dynamic return type.
This went largely unnoticed, since it’s buried deep in the Web API source code but it has some very useful repercussions for API developers.
Let’s have a look at the future.
Understanding the context π
Web API supports three types of possible action return values (well, four, if you count void):
-
- HttpResponseMessage
-
- IHttpActionResult
-
- any other type, subject to content negotiation
IHttpActionResult (effectively a factory for HttpResponseMessage) is the newest kid on the block, and very useful in some circumstances, but has been somewhat criticized in the community as being unnecessary abstraction.
Another problem was that once you marked an action as returning IHttpActionResult, you could only return implementations of this interface from it, preventing you from using HttpResponseMessage elsewhere in the action - and perhaps you only have a use case for IHttpActionResult in one of your code paths (you could do that only between HttpResponseMessage and regular object). A workaround has been to use the ResponseMessageResult which is an implementation of IHttpActionResult that wraps around HttpResponseMessage - but that feels like an unnecessary “hop”.
And this is exactly the problem that Web API 2.1 solves - as it makes total sense to be able to combine IHttpActionResult and HttpResponseMessage under single umbrella.
Dynamic action return π
In Web API 1 and 2, the return from your action was inspected statically inside the ApiControllerActionInvoker. That means the ActionDescriptor and its ReturnType property determined how your return was handled, not the runtime Type of that return object!
As a result the following was impossible in Web API 1 & 2:
//invalid in Web API 1 and 2
public class TestController : ApiController
{
[Route("test")]
public dynamic Get()
{
return Ok(); //IHttpActionResult
}
}
Because the IHttpActionResult has not been statically declared as the return type.
With Web API 2.1, it is perfectly fine to combine all three types of return objects together. Consider the following example:
public class Message
{
public string Text { get; set; }
}
public class TestController : ApiController
{
[Route("test/{id:int}")]
public dynamic Get(int id) //could be "object"
{
if (id < 5) return NotFound(); //IHttpActionResult if (id < 10) return Request.CreateResponse(HttpStatusCode.Gone); //HttpResponseMessage return new Message {Text = "hooray!" }; //regular Type, will be subject to conneg}} } }
We are able to branch the code and depending on the runtime context and return either IHttpActionResult, HttpResponseMessage or a regular object which we’d want Web API to content negotiate.
Now, the usage of a standard DTO here is a bit of a stretch, because the XML formatter will not work without static type information anyway - so whole solution will only work with JSON.
But it’s definitely very valuable to be able to branch code and choose between IHttpActionResult and raw HttpResponseMessage - and that’s the most important point of this blog post.