IHttpActionResult – new way of creating responses in ASP.NET Web API 2

Β· 1013 words Β· 5 minutes to read

In the first version of Web API, you had two ways of creating response from an API action. Either return a specific object instance (or void) and let the Web API pipeline convert that to an HttpResponseMessage for you, or return a raw HttpResponseMessage. In that case, you had to construct it manually, and you bypassed all of the internal Web API mechanisms (formatters, content negotiation).

Now in Web API 2 (which was just released in beta) we get a third option, which is IHttpActionResult. It’s very simple, yet extremely powerful - so let’s explore it in this blog post.

Adding ASP.NET Web API 2 beta πŸ”—

To be able to follow this blog post you’d need a new project with Web API 2 installed. This can be done very easily as the packages are now on Nuget.

I use a console app and a self host, so we’ll install a self host package.

Install-Package Microsoft.AspNet.WebApi.SelfHost -Pre  

This should pull v5.0.0-beta2 of ASP.NET Web API, otherwise known as Web API 2.

We’ll use a standard self host to play around:

class Program  
{  
static void Main(string[] args)  
{  
var config = new HttpSelfHostConfiguration("http://localhost:999");  
config.Routes.MapHttpRoute(  
name: "DefaultApi",  
routeTemplate: "api/{controller}/{id}",  
defaults: new { id = RouteParameter.Optional }  
);

var server = new HttpSelfHostServer(config);  
server.OpenAsync().Wait();

Console.ReadKey();

server.CloseAsync().Wait();  
}  
}  

Introducing IHttpActionResult πŸ”—

IHttpActionResult is not revolutionary in any way, as it simply builds around the familiar HttpResponseMessage, but it is tremendously useful. It is effectively a factory for HttpResponseMessage, and by implementing the interface you provide instructions on how a new response should be constructed.

The interface has just one method:

namespace System.Web.Http  
{  
public interface IHttpActionResult  
{  
Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken);  
}  
}  

Then, instead of returning an instance of an object or a raw HttpResponseMessage, you can return IHttpActionResult and Web API will follow your instructions coded in there.

With this in place, you get a hold of a powerful mechanism allowing you to re-use sets of instructions, to compose a specific type of response, between different actions - which in many ways is similar to what ASP.NET MVC does with its ActionResult.

Implementing a sample IHttpActionResult πŸ”—

One situation of where IHttpActionResult will come in handy is when you’d like to preset specific headers/properties of HTTP response. For example, when responding to a POST request, you’d like to automatically set the status code to 201 (created) and set the location header.

It’s very easy now:

public class CreatedContentActionResult : IHttpActionResult  
{  
private readonly HttpRequestMessage _request;  
private readonly string _location;

public CreatedContentActionResult(HttpRequestMessage request, string location)  
{  
_request = request;  
_location = location;  
}

public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)  
{  
var response = _request.CreateResponse(HttpStatusCode.Created);  
response.Headers.Location = new Uri(_location);  
return Task.FromResult(response);  
}  
}  

And you can use it in your controller just like that:

public class TestController : ApiController  
{  
public string Get(int id)  
{  
return "Hello " + id;  
}

public CreatedContentActionResult Post()  
{  
//dummy action for demo  
var id = new Random().Next(1, 100);  
return new CreatedContentActionResult(  
Request,  
Url.Link("DefaultApi", new {controller = "Test", id = id})  
);  
}  
}  

This will produce the desired output.

This way, instead of duplicating the code constructing such HttpResponseMessage across different controllers, or hiding it in some helper classes or a base class, we have a very verbose code base where we immediately know what’s being returned and under which circumstances.

Serving HTML with IHttpActionResult πŸ”—

Another great possible use case for IHttpActionResult is supporting HTML with Razor. You can now very easily define an HTML action result which would parse the Razor views.

This way you can build fully fledged web applications, with proper HTML templating support, and forget about MVC altogether.

Of course this is nothing new, because it was possible before with Web API too, using dedicated RazorMediaTypeFormatters (for example WebAPIContrib has a great one) - but it felt very hacky, as Web API didn’t lend itself to such uses cases well, especially if you wanted dedicated HTML pages (= not served via other media types).

With IHttpActionResult we can simply do something like this (mind you, this uses RazorEngine package from Nuget):

public class HtmlActionResult : IHttpActionResult  
{  
private const string ViewDirectory = @"E:devConsoleApplication8ConsoleApplication8&#8243;;  
private readonly string _view;  
private readonly dynamic _model;

public HtmlActionResult(string viewName, dynamic model)  
{  
_view = LoadView(viewName);  
_model = model;  
}

public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)  
{  
var response = new HttpResponseMessage(HttpStatusCode.OK);  
var parsedView = RazorEngine.Razor.Parse(\_view, \_model);  
response.Content = new StringContent(parsedView);  
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");  
return Task.FromResult(response);  
}

private static string LoadView(string name)  
{  
var view = File.ReadAllText(Path.Combine(ViewDirectory, name + ".cshtml"));  
return view;  
}  
}  

So we take in a view name and a model, and then read the view from the disk and parse it. Then we return an HttpResponseMessage with content type text/html based on that. By the way - because I’m demoing this against a self hosted console application I hardcoded the view folder in there too.

Now all we need is just a view:

  
</p> 

# Hello @Model.Title

@Model.Text

</body>  
</html>  

And a controller:

public class HtmlController : ApiController  
{  
public HtmlActionResult Get(string page)  
{  
return new HtmlActionResult(page,  
new {  
Title = "HTML in Web API",  
Text = "Now you can easily build any web app with Web API!"  
});  
}  
}  

Here I simply use the page variable from the route data to identify the view. We probably also want a separate route for the “html” side of our Web API application so I’ll throw it in too (after our default API route, since it’s very greedy):

config.Routes.MapHttpRoute(  
name: "DefaultPages",  
routeTemplate: "{page}",  
defaults: new { controller="Html" }  
);  

And now if we navigate to that controller in the browser, we get the HTML page served:

Summary πŸ”—

Overall, IHttpActionResult is extremely useful interface for Web API developers. It is something that was very needed - as an alternative to forcing developers to deal with formatters.

By declaring your own custom results, you can streamline lots of processes and easily achieve the desired output of your actions. And, as shown in the examples, you can even go beyond the pure API, and use Web API as an end-to-end robust web application platform with HTML serving.

About


Hi! I'm Filip W., a cloud architect from ZΓΌrich πŸ‡¨πŸ‡­. I like Toronto Maple Leafs πŸ‡¨πŸ‡¦, Rancid and quantum computing. Oh, and I love the Lowlands 🏴󠁧󠁒󠁳󠁣󠁴󠁿.

You can find me on Github and on Mastodon.

My Introduction to Quantum Computing with Q# and QDK book
Microsoft MVP