Generally, .NET Core web APIs accept request in JSON format and return the response in JSON format too. In this article, we will try to discuss more about how the return types are formatted and what are different factors which affect it.
ContentResult and JsonResult
IActionResult does not specify output format. The output formatters on web API project automatically decides the format in which data should be returned. We will shortly see how output formatters decide the output format. Let’s first look at two interesting return types – ContentResult and JsonResult.
If instead of IActionResult, you return JsonResult from the API, it would always return a json result. API would not honor any other information from request to decide if JSON format should be used or some other format should be used.
Similarly, if ContentResult type is used to return the response from API action, it would always return a plain text (string). The APIs can also return specific type. So if an API action decides to return a string, it would also emit a plain text result.
These two types of return types are very specific to particular response format (plain text and json). Regardless of preferences sent by client, these always output data in a specific format. And that’s the result these two types are special return types.
What is content negotiation ?
Content negotiation is a mechanism that can be used to serve different representations of the same resource at a given URI, providing ability to their clients to decide the best suited representations.
So, resource at given URI is basically an action in an API controller. Different representations can be XML representation, Json representation, etc. Client is any program that calls the resource (i.e. API action). A client can be a browser, or postman or any other tool or program.
So, we know what is definition of content negotiation. But practically how do client’s convey which representations of the response is best suited for them ?
How does it work ?
The key is Accept http header. This is the http header that is sent by client of the web API as a part of HTTP request. This http header specifies list of MIME types (different representations) that can be understood and are best suited for the client.
When this http header is received by .NET Core Web API Server, server tries to go through all different MIME types specified in the header to figure out a formatter that can produce the result in one of the formats specified in the header.
If no formatter was found, then
- It can return 406 Not Acceptable if MvcOptions.ReturnHttpNotAcceptable is set to
- Otherwise, .NET core API would try to find a formatter that can produce a result (in any format). First formatter which can format the return type is used.
If accept header is not specified, server decides the format in which response should be returned.
Return types and content negotiation
So if the API action returns IActionResult, .NET Core automatically wraps the object using ObjectResult concrete implementation and thus content negotiation support is added for those actions.
If an API action is returning a POCO object, .NET core automatically encapsulates it within an ObjectResult, hence content negotiation still works.
As stated earlier, if ContentResult and JsonResult return types are used, .NET core does not encapsulate the response inside ObjectResult(guess why ?). Hence, content negotiation does not work with these return types.
Browsers vs Non-Browser Clients
Browsers generally specify multiple MIME types in accept header. They may also specify wildcards. The default behavior from any .NET core web application is :
- Accept header coming from browser is ignored – if it is not configured to do otherwise
- Response is always returned in JSON format
If you wish to change this behavior,
RespectBrowserAcceptHeader is set to true as shown in below code example.
Non-browser clients may not have general HTTP standards implemented. Generally a web API can have non-browser clients e.g. phone app, desktop app, PowerShell script, etc. – which might send a specific MIME type in accept header that works best for them.
I hope you find this information useful. Let me know your thoughts.