ASP.NET Controllers Fundamentals

What are Controllers?

In ASP.NET Core, controllers are central to handling incoming HTTP requests. They are typically represented by classes that contain public methods called action methods. These action methods are responsible for processing requests, interacting with models, and ultimately returning responses, often by selecting a view to render or returning data directly (like JSON).

Controllers act as the intermediary between the client's request and the application's logic and data. They follow the Model-View-Controller (MVC) architectural pattern, which helps organize code into logical components, making applications more maintainable, testable, and scalable.

Controller Actions

Action methods are public methods within a controller class. When a request matches a route that points to a specific controller and action, that action method is executed. Action methods can accept parameters, which are typically bound from the incoming request (e.g., query string parameters, route data, or request body).

The return type of an action method determines the type of response sent back to the client. Common return types include:

Routing to Controllers

ASP.NET Core uses a powerful routing system to map incoming HTTP requests to the appropriate controller action. By default, it uses a convention-based router that looks for routes in the pattern /{controller}/{action}/{id}. However, you can customize routing extensively using attribute routing or by configuring routes in the Startup.cs or Program.cs file.

Attribute Routing: You can decorate your controller classes and action methods with attributes like [Route("api/[controller]")] or [HttpGet("details/{id}")] to define specific URL patterns that map directly to them.

Attribute routing provides more explicit control over URL structures and is generally preferred for its clarity and flexibility, especially in API development.

The Controller Base Class

ASP.NET Core provides a base class, Controller, from which most controllers inherit. This base class offers a wealth of functionality, including:

For API controllers, you'd typically inherit from ControllerBase or ApiController, which provides a lighter-weight set of features optimized for API scenarios.

Handling Requests

Controllers are designed to handle HTTP methods like GET, POST, PUT, DELETE, etc. You can specify which HTTP method an action method should handle using attributes like [HttpGet], [HttpPost], [HttpPut], [HttpDelete], or combined attributes like [AcceptVerbs("GET", "POST")].

Example: Handling different HTTP methods


using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    // Handles GET requests to /api/products
    [HttpGet]
    public IActionResult GetAllProducts()
    {
        // Logic to fetch all products
        return Ok(new[] { "Product A", "Product B" });
    }

    // Handles GET requests to /api/products/{id}
    [HttpGet("{id:int}")]
    public IActionResult GetProductById(int id)
    {
        // Logic to fetch product by ID
        if (id <= 0)
        {
            return BadRequest("Product ID must be a positive integer.");
        }
        return Ok($"Details for Product ID: {id}");
    }

    // Handles POST requests to /api/products
    [HttpPost]
    public IActionResult CreateProduct([FromBody] Product newProduct)
    {
        // Logic to create a new product
        // ...
        return CreatedAtAction(nameof(GetProductById), new { id = 123 }, newProduct);
    }

    // Handles PUT requests to /api/products/{id}
    [HttpPut("{id:int}")]
    public IActionResult UpdateProduct(int id, [FromBody] Product updatedProduct)
    {
        // Logic to update product with id
        return NoContent(); // Indicates success, no content to return
    }

    // Handles DELETE requests to /api/products/{id}
    [HttpDelete("{id:int}")]
    public IActionResult DeleteProduct(int id)
    {
        // Logic to delete product with id
        return Ok($"Product with ID {id} deleted.");
    }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
}
                

Passing Data to Views

When a controller action returns a ViewResult, it typically needs to pass data to the associated view. This can be achieved in several ways:

Example: Passing data to a view


using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

public class HomeController : Controller
{
    public IActionResult Index()
    {
        var items = new List<string> { "Item 1", "Item 2", "Item 3" };
        ViewBag.PageTitle = "Welcome to Our Site";
        ViewData["Message"] = "This is a message from ViewData.";
        
        // Passing a strongly-typed model
        var viewModel = new HomePageViewModel
        {
            FeaturedProducts = new List<Product>
            {
                new Product { Id = 1, Name = "Gadget Pro" },
                new Product { Id = 2, Name = "Tech Master" }
            }
        };

        return View(viewModel); // Passes viewModel to the view
    }
}

public class HomePageViewModel
{
    public List<Product> FeaturedProducts { get; set; }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
}
                

In your view (e.g., Views/Home/Index.cshtml), you would access these:


<h1>@ViewBag.PageTitle</h1>
<p>@ViewData["Message"]</p>

<h2>Featured Products:</h2>
<ul>
    @foreach (var product in Model.FeaturedProducts)
    {
        <li><a href="/products/@product.Id">@product.Name</a></li>
    }
</ul>
                

Examples

Here are some common controller scenarios:

Organize your controllers into logical folders (e.g., Controllers/Api, Controllers/Web) to maintain a clean project structure.