Introduction to Controllers
Controllers are the heart of an ASP.NET Core MVC application. They handle incoming browser requests, interact with the Model to retrieve data, and select a View to render the response. They bridge the gap between the user's input and the application's logic.
The Role of a Controller
- Request Handling: Controllers contain action methods that are executed in response to specific browser requests.
- Interacting with Models: They orchestrate calls to the Model layer to perform business logic and retrieve data.
- View Selection: Based on the data and logic, controllers choose which View to render and pass data to it.
- Response Generation: Controllers are responsible for constructing the HTTP response that is sent back to the browser.
Creating a Controller
Controllers are typically C# classes that inherit from the Controller base class provided by ASP.NET Core MVC. This base class offers many built-in features and helper methods.
using Microsoft.AspNetCore.Mvc;
public class HomeController : Controller
{
// Action methods go here
}
Action Methods
Action methods are public methods within a controller that are callable by the web application. They are identified by their return type, typically IActionResult or derived types like ViewResult, ContentResult, JsonResult, etc.
Example Action Method
using Microsoft.AspNetCore.Mvc;
public class ProductsController : Controller
{
public IActionResult Index()
{
// Logic to fetch products from a database or service
var products = new List<string> { "Laptop", "Keyboard", "Mouse" };
// Pass data to the view
return View(products);
}
public IActionResult Details(int id)
{
// Logic to fetch a specific product by ID
var productName = $"Product {id}";
return View("ProductDetails", productName); // Explicitly specifying the view name
}
public IActionResult GetProductInfo()
{
// Return data as JSON
var productData = new { Id = 1, Name = "Monitor", Price = 299.99 };
return Json(productData);
}
public IActionResult RedirectToAnotherPage()
{
// Redirect to another action method or URL
return RedirectToAction("Index", "Home");
}
public IActionResult ShowPlainContent()
{
return Content("This is plain text content.");
}
}
Routing to Controllers and Actions
ASP.NET Core MVC uses a routing system to map incoming URL requests to specific controller action methods. By default, the convention-based routing uses the URL pattern /Controller/Action/Id.
For example, a request to /products/index would map to the Index action method in the ProductsController.
Note: You can customize routing extensively using attributes or the startup configuration.
Controller Base Class Helpers
The Controller base class provides helpful properties and methods, such as:
View(): Returns aViewResult, typically rendering a view with the same name as the action.View(string viewName): Returns aViewResult, rendering a specific view.View(string viewName, object model): Renders a specific view and passes a model to it.RedirectToAction(string actionName): Performs an HTTP 302 redirect to an action.RedirectToRoute(string routeName): Redirects to a route specified by name.Json(object data): Returns aJsonResultwith the serialized data.Content(string content): Returns aContentResultwith plain text.BadRequest(),NotFound(),Ok(): CommonIActionResulthelpers for HTTP status codes.
Passing Data to Views
Data is passed from the controller to the view primarily through the action method's return type (using a model object) or by using the ViewBag or ViewData dynamic properties.
Using ViewBag
public IActionResult Index()
{
ViewBag.Message = "Welcome to our product catalog!";
ViewBag.ProductCount = 15;
return View();
}
In the corresponding view:
<h2>@ViewBag.Message</h2>
<p>We have @ViewBag.ProductCount items in stock.</p>
Controller Lifecycle and Dependency Injection
Controllers can leverage Dependency Injection (DI). Services can be injected into controller constructors, allowing for cleaner code and better testability.
public class ServicesController : Controller
{
private readonly IProductService _productService;
// Constructor injection
public ServicesController(IProductService productService)
{
_productService = productService;
}
public IActionResult ListProducts()
{
var products = _productService.GetAllProducts();
return View(products);
}
}
Advanced Controller Concepts
Controller Naming Conventions
Controller classes are typically named by appending "Controller" to the logical name of the controller, e.g., HomeController, ProductsController, AccountController.
Action Result Types
Understanding the various IActionResult implementations is crucial for returning different types of responses:
ViewResult: Renders an HTML view.PartialViewResult: Renders a partial HTML view.JsonResult: Returns JSON data.ContentResult: Returns plain text or HTML.RedirectResult: Performs an HTTP redirect to a specified URL.RedirectToActionResult: Redirects to another action within the same controller or a different controller.StatusCodeResult: Returns a specified HTTP status code.EmptyResult: Returns an empty response.
Model Binding
ASP.NET Core MVC automatically binds incoming request data (from the query string, form data, route data, etc.) to action method parameters. This significantly simplifies data handling.
// Request: /users/update?id=123&name=Alice
public IActionResult Update(int id, string name)
{
// 'id' is 123, 'name' is "Alice"
return Ok($"User {name} with ID {id} updated.");
}
// Binding complex objects
public class UserUpdateModel
{
public int UserId { get; set; }
public string NewUserName { get; set; }
}
// Request: /users/update-user
// Body: { "UserId": 456, "NewUserName": "Bob" }
public IActionResult UpdateUser([FromBody] UserUpdateModel model)
{
// 'model.UserId' is 456, 'model.NewUserName' is "Bob"
return Ok($"User {model.NewUserName} with ID {model.UserId} updated via JSON.");
}
Action Filters
Action filters allow you to inject cross-cutting concerns into the MVC pipeline, such as authorization, logging, caching, and error handling. They can be applied at the controller level or the action method level.
// Example: Simple Authorization Filter
public class AdminAuthAttribute : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
// Check if user is authenticated and has admin role
if (!context.HttpContext.User.Identity.IsAuthenticated || !context.HttpContext.User.IsInRole("Admin"))
{
context.Result = new ForbidResult(); // Or RedirectToPage("/Account/AccessDenied")
}
}
}
// Applying the filter
[Authorize(Roles = "Admin")] // Built-in authorization filter
public class AdminController : Controller
{
public IActionResult Index()
{
return View();
}
[AdminAuth] // Custom filter
public IActionResult ManageUsers()
{
return View();
}
}