11

After reading this blog post on how to return HTML from Web API 2 using IHttpActionResult, I wanted to somehow "wire-up" this IHttpActionResult to my ApiController based on the Accept header that is sent with request.

Given controller actions that have signature similar to this:

public MyObject Get(int id)
{
    return new MyObject();
}

If the request specifies the Accept: text/html, this IHttpActionResult should be used to return HTML. Is that possible? In addition, some insight on how this content negotiation pipeline works for json or xml (that have built-in support) would be greatly appreciated.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
cvbarros
  • 1,684
  • 1
  • 12
  • 19
  • 1
    Just ask yourself what would **you** expect to get as HTML response from this action? Spans, divs, labels, table? While with json and xml it is more or less predictable because of their nature, it's hard to come up with something generic for HTML. You should generate it manually and return it along with a correct response headers. – Ramunas Jan 30 '14 at 22:44
  • I will use RazorEngine to render the object in a view, I'm not looking for a bullet-proof "generic" solution. So it will be manually generated for each return type. – cvbarros Jan 30 '14 at 23:27
  • WebAPI with Razor? Looks like a normal ASP.NET MVC – Ramunas Jan 31 '14 at 05:16

1 Answers1

13

If we keep the discussion of IHttpActionResult aside for a momment, Content-negotiation process in Web API is driven through formatters. So you would need to create a new formatter for handling the media type text/html.

Web API exposes the default algorithm it uses for content-negotiation called DefaultContentNegotiator which is an implementation of the service IContentNegotiator.

Now this negotiation algorithm can be run either by Web API automatically for you like in the following cases:

Usage # 1:

public MyObject Get(int id)
{
   return new MyObject();
}

OR

you can manually run the negotiation yourself like in the following:

Usage #2 :

public HttpResponseMessage Get()
{
    HttpResponseMessage response = new HttpResponseMessage();

    IContentNegotiator defaultNegotiator = this.Configuration.Services.GetContentNegotiator();
    ContentNegotiationResult negotationResult = defaultNegotiator.Negotiate(typeof(string), this.Request, this.Configuration.Formatters);

    response.Content = new ObjectContent<string>("Hello", negotationResult.Formatter, negotationResult.MediaType);
    return response;
}

Regarding IHttpActionResults:
In the following scenario, Ok<> is a shortcut method for generating an instance of type OkNegotiatedContentResult<>.

public IHttpActionResult Get()
{
    return Ok<string>("Hello");
}

The thing is this OkNegotiatedContentResult<> type does similar thing as in Usage # 2 scenario above. i.e they run the negotiator internally.

So to conclude, if you plan to support text/html media type then you need to write a custom formatter and add it to Web API's formatter collection and then when you use Ok<string>("Hello") with an Accept header of text/html, you should see the response in text/html. Hope this helps.

DaveRead
  • 3,371
  • 1
  • 21
  • 24
Kiran
  • 56,921
  • 15
  • 176
  • 161
  • Thanks, Kiran. I ended up using the Usage #1 with the WebApiContrib.Formatting.Razor project that has a built-in ViewLocator and media type formatter for Razor. Thanks for your help!https://github.com/WebApiContrib/WebApiContrib.Formatting.Razor – cvbarros Jan 31 '14 at 12:54