ADVERTISEMENT
Google AdSense Slot (headerLeaderboard)

Set your Publisher ID in src/config/ads.ts to display live ads.

ASP.NET Core Tutorial• 8 min read

Controller-Based Web APIs & Routing

Building RESTful resources with [ApiController], [Route], and ActionResult<T>

Controller-based APIs provide structured, attribute-driven routing for large enterprise architectures where separation of concerns and clear domain boundaries are paramount.

Key Controller Attributes and Response Types

[ApiController]: Enables automatic model validation, attribute routing enforcement, and standard 400 ProblemDetails error responses.

[Route("api/[controller]")]: Sets the route prefix automatically based on class name (e.g., CoursesController becomes /api/courses).

ActionResult<T>: Allows returning both HTTP status codes (NotFound(), BadRequest(), CreatedAtAction()) and strongly-typed objects (Ok(model)).

Production API Controller (Controllers/CoursesController.cs)
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
public class CoursesController : ControllerBase
{
    private static readonly List<CourseDto> _db = new()
    {
        new CourseDto(1, "Modern ASP.NET Core", 129.99m),
        new CourseDto(2, "Advanced C# 12", 99.99m)
    };

    [HttpGet]
    public ActionResult<IEnumerable<CourseDto>> GetAll() => Ok(_db);

    [HttpGet("{id:int}")]
    public ActionResult<CourseDto> GetById(int id)
    {
        var course = _db.FirstOrDefault(c => c.Id == id);
        if (course == null)
            return NotFound(new { Message = $"Course with ID {id} does not exist." });
            
        return Ok(course);
    }

    [HttpPost]
    public ActionResult<CourseDto> Create([FromBody] CourseDto newCourse)
    {
        _db.Add(newCourse);
        return CreatedAtAction(nameof(GetById), new { id = newCourse.Id }, newCourse);
    }
}

public record CourseDto(int Id, string Title, decimal Price);
CreatedAtAction returns HTTP 201 Created with a Location header pointing to the new resource.
ADVERTISEMENT
Google AdSense Slot (inContentBanner)

Set your Publisher ID in src/config/ads.ts to display live ads.

Test Yourself With Exercise

+15 XP

Which attribute automatically triggers 400 Bad Request responses when model validation rules fail in ASP.NET Core?