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.
There are two kinds of content negotiation which are possible in HTTP: server-driven and agent-driven negotiation. These two kinds of negotiation are orthogonal and thus may be used separately or in combination.
The Accept header tells the server what formats or MIME types that the client is looking for. You can use the HTTP Accept headers to determine the content format used to exchange data. While the Accept header is not as visible as URLs or parameters, this header is a more flexible method of handling content negotiation.
In Web API, content negotiation is performed by the runtime (at the server side) to determine the media type formatter to be used based to return the response for an incoming request from the client side. Content negotiation is centered on Media type and Media type formatter.
Content negotiation is the process of selecting one of multiple possible representations to return to a client, based on client or server preferences.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With