Introduction to API Controllers
API Controllers are the backbone of building web APIs in ASP.NET Core. They handle incoming HTTP requests, process them, and return HTTP responses. They are designed specifically for creating HTTP services and leverage ASP.NET Core's powerful features for routing, request binding, model validation, and more.
Unlike traditional MVC controllers that often return views, API controllers primarily return data, typically in formats like JSON or XML, which are consumed by clients such as single-page applications (SPAs), mobile apps, or other services.
Creating API Controllers
To create an API Controller, you typically inherit from the ControllerBase
class or the Controller
class (if you need support for views, though this is less common for pure APIs).
ControllerBase
provides the core functionality for API controllers, including:
- Access to
HttpContext
,Request
, andResponse
. - Action result types (e.g.,
OkResult
,NotFoundResult
,JsonResult
). - Model validation.
- Dependency Injection capabilities.
Here's a simple example of an API Controller:
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
// In-memory data store for demonstration
private static List<Product> _products = new List<Product>
{
new Product { Id = 1, Name = "Laptop", Price = 1200.00M },
new Product { Id = 2, Name = "Keyboard", Price = 75.00M }
};
[HttpGet]
public ActionResult<IEnumerable<Product>> GetProducts()
{
return Ok(_products);
}
[HttpGet("{id}")]
public ActionResult<Product> GetProduct(int id)
{
var product = _products.Find(p => p.Id == id);
if (product == null)
{
return NotFound(); // Returns HTTP 404 Not Found
}
return Ok(product); // Returns HTTP 200 OK with product data
}
[HttpPost]
public ActionResult<Product> CreateProduct([FromBody] Product newProduct)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState); // Returns HTTP 400 Bad Request
}
newProduct.Id = _products.Count + 1;
_products.Add(newProduct);
return CreatedAtAction(nameof(GetProduct), new { id = newProduct.Id }, newProduct); // Returns HTTP 201 Created
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
Action Methods
Action methods within an API controller are public methods that handle specific HTTP requests. They are identified by HTTP verb attributes like [HttpGet]
, [HttpPost]
, [HttpPut]
, [HttpDelete]
, and [HttpPatch]
.
- Return Types: Action methods can return various types, including primitive types, complex objects, or
IActionResult
. ReturningIActionResult
provides more control over the HTTP response, such as status codes and headers. - Parameters: Parameters can be bound from the request body (using
[FromBody]
), route (e.g.,[HttpGet("{id}")]
), query string (e.g.,[HttpGet] public IActionResult Get(int pageNumber)
), or headers.
Routing
ASP.NET Core uses a routing mechanism to map incoming HTTP requests to specific action methods. The [Route]
attribute is commonly used to define routes for controllers and action methods.
[ApiController]
Attribute: This attribute enables several API-specific behaviors, including automatic model validation, handling of common HTTP response types, and implicit routing conventions.- Convention-Based Routing: The
[Route("api/[controller]")]
attribute on the controller class defines a route template.[controller]
is a placeholder that gets replaced by the controller's name (e.g., "Products" forProductsController
). - Action-Level Routing: Further customization of routes can be done at the action method level, often specifying the HTTP verb and route parameters.
Request Processing
API Controllers streamline request processing through:
- Model Binding: Automatically maps incoming request data (from route, query string, body, etc.) to action method parameters.
- Model Validation: The
[ApiController]
attribute automatically performs model validation. If validation fails, aBadRequest
response with validation errors is returned.
Response Generation
API Controllers generate HTTP responses using IActionResult
and its derived types.
Ok()
: Returns an HTTP 200 OK status.NotFound()
: Returns an HTTP 404 Not Found status.BadRequest()
: Returns an HTTP 400 Bad Request status.CreatedAtAction()
: Returns an HTTP 201 Created status, often including aLocation
header pointing to the newly created resource.NoContent()
: Returns an HTTP 204 No Content status, typically used for successful PUT or DELETE operations where no response body is needed.
Content Negotiation
ASP.NET Core's API Controllers automatically handle content negotiation. When a client sends an Accept
header (e.g., Accept: application/json
), the framework attempts to serialize the response data into the requested format.
- JSON is Default: JSON is the most common format for web APIs and is well-supported by default.
- XML Support: You can enable XML support by adding the necessary NuGet packages and configuration.
Error Handling
Robust error handling is crucial for APIs. ASP.NET Core provides several mechanisms:
- Action Result Types: As mentioned, using appropriate
IActionResult
types (e.g.,NotFound
,BadRequest
) provides clear error status codes. - Global Exception Handling: Middleware can be configured to catch unhandled exceptions and return a consistent error response to the client.
[ApiController]
Attributes: Automatically returnsBadRequest
for model validation failures.
Dependency Injection
API Controllers fully integrate with ASP.NET Core's built-in dependency injection system. You can inject services into your controllers through their constructors.
public class MyServiceController : ControllerBase
{
private readonly IMyService _myService;
public MyServiceController(IMyService myService)
{
_myService = myService;
}
[HttpGet]
public IActionResult GetSomeData()
{
var data = _myService.GetData();
return Ok(data);
}
}
Testing API Controllers
Unit testing and integration testing are essential for ensuring your API functions correctly.
- Unit Testing: You can unit test individual action methods by mocking dependencies and using the
ControllerBase.ControllerContext
to simulate a request. - Integration Testing: ASP.NET Core's
TestServer
andHttpClient
are invaluable for writing integration tests that simulate real HTTP requests against your API.