ASP.NET Core MVC Controllers and Action Methods
In ASP.NET Core Model-View-Controller (MVC), controllers and action methods serve as the central coordinators of web applications. This article breaks down how incoming HTTP requests are received by controllers, processed through specific C# action methods, integrated with model binding, and returned to the client as views, JSON data, or HTTP status codes.
The Role of a Controller
A controller is a C# class that orchestrates application logic by
accepting HTTP requests, interacting with data models or services, and
selecting an appropriate response. In traditional ASP.NET Core MVC, a
controller typically inherits from the built-in
Microsoft.AspNetCore.Mvc.Controller class.
Inheriting from Controller provides access to core MVC
features, including the HttpContext,
ModelState, and helper methods for rendering views (such as
View(), PartialView(), and
RedirectToAction()). By convention, controller class names
end with the suffix "Controller" (e.g., HomeController),
which the framework's routing engine uses to identify valid
endpoints.
Understanding Action Methods
Action methods are public methods defined within a controller that
execute in response to an incoming URL. Any public method inside a
controller class is treated as an action method unless explicitly
decorated with the [NonAction] attribute.
Action methods can be restricted to specific HTTP verbs using
attributes such as [HttpGet], [HttpPost],
[HttpPut], and [HttpDelete]. By default, an
action method responds to GET requests if no HTTP method
attribute is specified.
Routing and the Request Lifecycle
When a client sends a request to an ASP.NET Core application, the
routing middleware inspects the URL to determine which controller and
action method should execute. Traditional MVC uses conventional routing,
defined in the Program.cs file:
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");With this pattern, a request to /Products/Details/5
triggers the following lifecycle:
- The routing engine parses the URL and identifies the
ProductsController. - It looks for a public method named
Detailson that controller. - It passes the value
5as an argument to the method's parameter.
Alternatively, developers can use attribute routing by decorating
controllers and actions directly with [Route("...")]
attributes.
Model Binding
Before an action method executes, ASP.NET Core uses model binding to extract data from the HTTP request and populate the action method's parameters. The framework searches multiple sources in a defined order:
- Form fields (from POST requests)
- The request body (such as JSON data)
- Route values (from URL segments like
{id}) - Query strings (from URL parameters like
?id=5) - Uploaded files
Model binding automatically handles data type conversions (e.g.,
parsing a string from a query string into a C# int or
DateTime) and runs validation attributes defined on the
model, storing errors in ModelState.
Action Results
Action methods process data and return a type that implements the
IActionResult interface. This allows the method to define
how the framework should respond to the client. Common return types
include:
- ViewResult (
View()): Renders an HTML Razor view using data passed to it via a model. - JsonResult (
Json()): Serializes an object to JSON, useful for AJAX requests. - RedirectToActionResult
(
RedirectToAction()): Issues an HTTP 302 redirect to another action method. - NotFoundResult (
NotFound()): Returns an HTTP 404 status code. - StatusCodeResult (
StatusCode()): Returns a specific HTTP status code, such as 200, 400, or 500.
Code Example
Below is a complete implementation of a controller managing product data:
using Microsoft.AspNetCore.Mvc;
public class ProductsController : Controller
{
// Responds to: GET /Products/Details/5
[HttpGet]
public IActionResult Details(int? id)
{
if (id == null)
{
return NotFound();
}
var product = new Product { Id = id.Value, Name = "Sample Item" };
return View(product);
}
// Responds to: POST /Products/Create
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Product product)
{
if (!ModelState.IsValid)
{
return View(product);
}
// Save logic executed here
return RedirectToAction(nameof(Details), new { id = product.Id });
}
}Through this mechanism, ASP.NET Core MVC maintains a clean separation of concerns: controllers handle the flow of application execution, models represent business data and rules, and views handle UI presentation.