Basic Controller
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")] // → /api/products
public class ProductsController : ControllerBase {
[HttpGet] // GET /api/products
public IActionResult GetAll() {
return Ok(new[] { "Pen", "Book" });
}
[HttpGet("{id}")] // GET /api/products/5
public IActionResult GetById(int id) {
if (id < 1) return BadRequest("Invalid id");
return Ok(new { Id = id, Name = "Pen" });
}
[HttpPost] // POST /api/products
public IActionResult Create([FromBody] ProductDto dto) {
// create logic
return CreatedAtAction(nameof(GetById), new { id = 1 }, dto);
}
[HttpPut("{id}")] // PUT /api/products/5
public IActionResult Update(int id, [FromBody] ProductDto dto) {
return NoContent();
}
[HttpDelete("{id}")] // DELETE /api/products/5
public IActionResult Delete(int id) {
return NoContent();
}
}
Routing
// Conventional (Program.cs)
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
// Attribute routing ⭐
[Route("api/v1/users")]
[Route("api/[controller]")] // [controller] = class name without "Controller"
// Multiple routes
[HttpGet]
[Route("active")]
[Route("status/active")]
public IActionResult GetActive() { ... }
// Route constraints
[HttpGet("{id:int:min(1)}")]
[HttpGet("{slug:alpha:length(3,50)}")]
[HttpGet("{date:datetime}")]
IActionResult vs ActionResult<T>
// IActionResult — generic, less type info
public IActionResult Get() => Ok(user);
// ActionResult<T> ⭐ — both type + status
public ActionResult<User> Get(int id) {
var user = _db.Users.Find(id);
if (user == null) return NotFound();
return user; // implicit Ok()
}
Response Helpers
return Ok(data); // 200
return Created("/api/users/5", user); // 201
return CreatedAtAction(nameof(Get), new { id = 5 }, user);
return NoContent(); // 204
return BadRequest("Invalid"); // 400
return Unauthorized(); // 401
return Forbid(); // 403
return NotFound(); // 404
return Conflict("Duplicate"); // 409
return UnprocessableEntity(errors); // 422
return StatusCode(500, "Server error");
return File(bytes, "application/pdf");
Parameter Binding
[HttpGet("{id}")]
public IActionResult Get(
[FromRoute] int id, // URL path
[FromQuery] string search, // ?search=xxx
[FromHeader(Name="X-Api-Key")] string apiKey, // header
[FromBody] UserDto dto // JSON body
) { ... }
Minimal API (.NET 6+)
// Program.cs — Controller-less
app.MapGet("/api/products", () => new[] { "Pen", "Book" });
app.MapGet("/api/products/{id:int}", (int id) => {
return Results.Ok(new { Id = id });
});
app.MapPost("/api/products", (ProductDto dto) =>
Results.Created($"/api/products/1", dto));