⚙️

ASP.NET Core MVC Routing

Understanding and configuring URL routing in your web applications.

Introduction to MVC Routing

Routing is a core concept in ASP.NET Core MVC. It determines how incoming browser requests are mapped to the correct action method in your controllers. By defining routes, you control the structure of the URLs your application exposes, making them user-friendly and SEO-friendly.

ASP.NET Core MVC uses a convention-based routing system that's highly flexible. You define a route template that includes placeholders for segments like controller, action, and optional parameters.

Default Routing Convention

By default, ASP.NET Core MVC applications are configured to use a "Conventional Routing" approach. The standard route template is often defined as follows:

Default Route Template
/{controller}/{action}/{id?}

Let's break this down:

  • {controller}: This placeholder represents the name of the controller. For example, a request to /Home/Index would map to the Index action of the HomeController.
  • {action}: This placeholder represents the name of the action method within the controller.
  • {id?}: This is an optional parameter. The question mark (?) indicates that this segment is optional. It's commonly used to pass an identifier, such as a primary key for a resource.

If you don't specify an action, the default action (usually Index) will be invoked.

If you don't specify a controller, the default controller (usually Home) will be used.

Configuring Routes in Startup.cs (or Program.cs)

The routing configuration is typically done in the Configure method of your Startup.cs file (or directly in Program.cs for newer .NET versions using minimal APIs). This is where you register the routing middleware.

Using UseRouting() and UseEndpoints()

In modern ASP.NET Core applications, routing is handled by two key middleware components:

  • UseRouting(): This middleware adds the routing services to the request pipeline and discovers endpoints.
  • UseEndpoints(): This middleware runs the selected endpoint, which typically involves invoking an MVC controller action.
Example in Program.cs (Minimal APIs)
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting(); // Enable endpoint routing

app.UseAuthorization();

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

app.Run();
Note: For older .NET Core versions using the Startup.cs class, the configuration would look similar within the Configure method:
app.UseRouting();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});

Custom Route Templates

You're not limited to the default routing pattern. You can define custom routes to create more specific or user-friendly URLs. This is particularly useful for creating cleaner URLs for product pages, blog posts, or specific feature endpoints.

Example: Product Route

Let's say you want URLs like /products/details/my-awesome-product-slug. You can define a custom route like this:

Custom Product Route
endpoints.MapControllerRoute(
    name: "productdetails",
    pattern: "products/details/{slug?}", // Custom pattern with a slug parameter
    defaults: new { controller = "Products", action = "Details" });

In this example:

  • name: "productdetails": A unique name for this route.
  • pattern: "products/details/{slug?}": The URL pattern. It starts with a fixed path "products/details" and includes an optional slug parameter.
  • defaults: new { controller = "Products", action = "Details" }: Specifies the default controller and action if these are not provided in the URL.

Attribute Routing

Attribute routing offers an even more declarative way to define routes directly on your controller actions using attributes. This approach embeds routing information directly within your code, making it easy to see which URL maps to which action.

Example: Attribute Routing

To use attribute routing, you need to ensure MapAttributeRoutes() is called in your UseEndpoints configuration.

Program.cs with Attribute Routing
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers(); // This maps attribute-routed controllers
    // You can still have conventional routes alongside attribute routes
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});

Now, decorate your controller actions with the [Route] attribute:

Controller with Attribute Routing
using Microsoft.AspNetCore.Mvc;

namespace MyWebApp.Controllers
{
    public class CatalogController : Controller
    {
        [Route("catalog")] // Maps to CatalogController.Index()
        [Route("catalog/all")] // Also maps to CatalogController.Index()
        public IActionResult Index()
        {
            return View();
        }

        [Route("catalog/items/{category}")] // Maps to CatalogController.Items(string category)
        public IActionResult Items(string category)
        {
            ViewBag.Category = category;
            return View();
        }

        [HttpGet("products/{id:int}")] // Maps to CatalogController.ProductDetail(int id) with GET method
        public IActionResult ProductDetail(int id)
        {
            ViewBag.ProductId = id;
            return View();
        }
    }
}

Notice the use of route constraints (:int) and HTTP method constraints ([HttpGet]) for even more precise routing.

Route Constraints

Route constraints allow you to specify rules for the values of route parameters. This ensures that only requests matching the constraint will be routed to the specified action.

  • int: Parameter must be an integer.
  • alpha: Parameter must contain only alphabetic characters.
  • guid: Parameter must be a GUID.
  • datetime: Parameter must be a valid date and time.
  • {parameter:regex(your_pattern)}: Custom regular expression.