ASP.NET Core MVC Routing

This tutorial explores the fundamental concepts of routing in ASP.NET Core MVC, enabling you to define how incoming HTTP requests are mapped to controller actions.

Introduction

Routing is a critical component of any web application. It determines which code runs when a user requests a specific URL. In ASP.NET Core MVC, routing is highly configurable, allowing for flexible and powerful URL structures.

Routing Basics

At its core, routing involves matching an incoming request URL against a set of defined routes. Each route is essentially a pattern that can capture parts of the URL and bind them to parameters for your controller actions.

Traditionally, ASP.NET Core MVC used a configuration-based approach in Startup.cs (or Program.cs in .NET 6+). Here's a common setup:

// In Startup.cs (Configure method) or Program.cs

app.UseRouting();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});
                

This "default" route is a convention that looks for:

Attribute Routing

Attribute routing offers a more declarative and often more readable way to define routes directly on your controllers and actions using attributes. This is the recommended approach for most modern ASP.NET Core applications.

To enable attribute routing, you need to call MapAttributeRoutes:

// In Startup.cs (Configure method) or Program.cs

app.UseRouting();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers(); // For controllers using attribute routing
});
                

Then, you can decorate your controller actions:

using Microsoft.AspNetCore.Mvc;

public class ProductsController : Controller
{
    [HttpGet("/products")]
    public IActionResult List()
    {
        return View();
    }

    [HttpGet("/products/{id:int}")]
    public IActionResult Details(int id)
    {
        // Logic to fetch product by id
        return View();
    }
}
                

Route Constraints

Route constraints allow you to specify requirements for route parameters, ensuring that only URLs matching these constraints are routed to the corresponding action. This is particularly useful with attribute routing.

Common constraints include:

[HttpGet("/users/{username:minlength(3):maxlength(15)}")]
public IActionResult UserProfile(string username)
{
    // ...
    return View();
}

[HttpGet("/articles/{year:int:range(2000, 2023)}/{month:int:range(1, 12)}")]
public IActionResult Archive(int year, int month)
{
    // ...
    return View();
}
                

Route Templates

Route templates define the structure of your URLs. They can include literal values, route parameters, and optional segments.

Literal values: These are fixed parts of the URL, like /api/v1.

Route parameters: These are placeholders that capture parts of the URL, enclosed in curly braces, e.g., {id}.

Optional parameters: Parameters can be made optional by appending a question mark, e.g., {id?}.

Route Parameters

Route parameters are segments in the URL that are captured and passed as arguments to your controller actions. The names of the parameters in the route template must match the names of the parameters in your action method.

// Route: /customers/123
[HttpGet("/customers/{customerId}")]
public IActionResult CustomerDetails(int customerId)
{
    // customerId will be 123
    return View();
}
                

Optional Parameters

You can define optional parameters in your route templates by appending a question mark (?) to the parameter name. If the parameter is not present in the URL, its corresponding action parameter will receive its default value (usually null for reference types or the default value for value types).

// URL: /orders OR /orders/5
[HttpGet("/orders/{orderId?}")]
public IActionResult OrderDetails(int? orderId)
{
    if (orderId.HasValue)
    {
        // Show specific order details
    }
    else
    {
        // Show list of orders
    }
    return View();
}
                

Default Values

You can specify default values for route parameters directly within the route template. If a parameter is missing in the URL and has a default value defined, that default value will be used.

// URL: /reports OR /reports/sales
[HttpGet("/reports/{reportType=summary}")]
public IActionResult GenerateReport(string reportType)
{
    // If URL is /reports, reportType will be "summary"
    // If URL is /reports/sales, reportType will be "sales"
    return View();
}
                

Complex Routes

Attribute routing makes it easy to define complex and specific URL patterns:

[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
public class ItemsController : ControllerBase
{
    [HttpGet("{id:Guid}")]
    [MapToApiVersion("1.0")]
    public IActionResult GetItem(Guid id) { ... }

    [HttpPost]
    [MapToApiVersion("1.0")]
    public IActionResult CreateItem([FromBody] Item newItem) { ... }
}
                

The [Route] attribute on the controller class applies a base route template to all actions within that controller. Action-level attributes then append to or override this base.

Summary

Mastering routing is essential for building well-structured and user-friendly ASP.NET Core MVC applications. Attribute routing, with its clear syntax and powerful features like constraints and defaults, provides an elegant solution for mapping URLs to your application logic.

Continue learning by exploring API Versioning and Middleware in ASP.NET Core.