Keywords: ASP.NET Core | JSON | HTTP Status Code | Web API | Content Negotiation
Abstract: This article provides an in-depth exploration of how to correctly return JSON responses and control HTTP status codes in ASP.NET Core Web API. By analyzing core concepts such as ActionResult and IActionResult, along with code examples and configuration guides, it assists developers in migrating from Web API 2 to .NET Core, covering advanced topics like content negotiation and custom formatters to ensure flexible and consistent API responses.
Introduction
When developing ASP.NET Core Web APIs, many developers migrating from earlier versions of Web API often face challenges in returning JSON data while specifying HTTP status codes. For instance, in Web API 2, using IHttpActionResult and the Content method made this straightforward, but in .NET Core, these interfaces have been replaced by ActionResult and IActionResult. Based on Q&A data and reference articles, this article delves into efficient methods for handling JSON responses and status codes in ASP.NET Core, covering aspects from basic configuration to advanced customization.
Core Concepts: ActionResult and IActionResult
In ASP.NET Core, controller actions can return various types, with ActionResult and IActionResult being key interfaces for encapsulating HTTP responses. IActionResult is a more general interface that allows actions to return different types of results, while ActionResult is one of its concrete implementations. By leveraging these interfaces, developers can flexibly control the status code and content format of responses. For example, when returning a POCO (Plain Old CLR Object), the runtime automatically wraps it in an ObjectResult and serializes the data using the appropriate output formatter based on content negotiation.
Using Helper Methods for Status Code Control
ASP.NET Core offers a rich set of helper methods for returning common HTTP status codes while supporting JSON data serialization. These methods are based on ObjectResult and include built-in content negotiation. For instance, Ok(result) returns a 200 status code with JSON-formatted data, NotFound() returns a 404 status code, and BadRequest() returns a 400 status code. The following code example demonstrates how to use these methods in an action:
public IActionResult Search(string namelike)
{
var result = _authorRepository.GetByNameSubstring(namelike);
if (!result.Any())
{
return NotFound(namelike);
}
return Ok(result);
}In this example, if the query results are empty, a 404 status code is returned; otherwise, a 200 status code with JSON data is provided. This approach simplifies code, enhances readability, and avoids the complexity of manually setting status codes.
Configuring MVC Services
To ensure that a Web API correctly responds with JSON data, it is essential to configure MVC services during application startup. By default, using the AddMvc() method adds JSON input and output formatters, along with other necessary services. However, for finer control, the AddMvcCore() method can be used to manually add services, such as custom formatters or adjustments to content negotiation behavior. Here is a configuration example:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore(options =>
{
options.RequireHttpsPermanent = true;
options.RespectBrowserAcceptHeader = true;
})
.AddFormatterMappings()
.AddJsonFormatters();
}By setting RespectBrowserAcceptHeader to true, the application respects the client's Accept header, enabling content negotiation. If not set, by default, the browser's Accept header is ignored, and JSON format is always returned to ensure consistency across browsers.
Content Negotiation and Format Selection
Content negotiation is a key feature in ASP.NET Core, allowing the server to return data in different formats based on the client's Accept header. Default supported media types include application/json, text/json, and text/plain. When a client sends a request, the server enumerates the media types in the Accept header and selects the first available formatter. If no matching formatter is found, the server may return a 406 Not Acceptable status code or use the default formatter. For example, if a client requests XML format but the server only has JSON formatters configured, the response will still be in JSON. Developers can extend support by adding XML formatters:
services.AddControllers().AddXmlSerializerFormatters();This allows controller actions to return JSON or XML data based on the Accept header.
Code Examples: From Basic to Advanced
The following code examples illustrate how to return JSON and status codes in an ASP.NET Core Web API. First, a simple action returns a JsonResult, but this does not provide control over status codes:
public JsonResult Get()
{
return Json(_authorRepository.List());
}To control status codes, use IActionResult with helper methods:
public IActionResult GetById(long id)
{
var item = _itemRepository.GetById(id);
if (item == null)
{
return NotFound();
}
return Ok(item);
}For custom status codes, the StatusCode method can be employed:
public IActionResult CustomStatus()
{
return StatusCode(418, new { message = "I'm a teapot" });
}These examples highlight the benefits of using built-in methods, such as improved code maintainability and avoidance of repetitive response header settings.
Advanced Configuration and Customization
For advanced scenarios, developers can customize output formatters or use filters to enforce specific formats. For example, applying the [Produces] filter can force a controller or action to return JSON format, ignoring the client's Accept header:
[Produces("application/json")]
public class AuthorsController : ControllerBase
{
// All actions return JSON by default
}Additionally, default formatters like StringOutputFormatter or HttpNoContentOutputFormatter can be removed to alter the behavior for null values or strings. For instance, after removing HttpNoContentOutputFormatter, returning a null object results in the JSON formatter returning a null body instead of a 204 No Content status code.
Conclusion
Best practices for returning JSON and HTTP status codes in ASP.NET Core involve using IActionResult and built-in helper methods like Ok, NotFound, etc., to simplify code and enhance readability. By properly configuring MVC services and supporting content negotiation, APIs can flexibly respond to diverse client needs. For advanced use cases, custom formatters and filters offer additional control. When migrating from Web API 2, understanding these core concepts enables developers to quickly adapt to the new framework and build efficient, maintainable Web APIs.