ASP.NET Core MVC Controllers

Understand the core of ASP.NET Core MVC web applications.

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

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:

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:

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();
    }
}
            
Next: Working with Views