Routing in ASP.NET Core
Routing is the process of determining how an incoming request to an ASP.NET Core application is handled. It maps incoming HTTP requests to specific code that handles those requests.
What is Routing?
In web development, a route is a URL pattern that is linked to a particular handler (a controller action, a Razor Page, or a minimal API endpoint). When a user or client sends an HTTP request to a specific URL, the routing system in ASP.NET Core analyzes the URL and compares it against the defined routes. If a match is found, the corresponding handler is executed.
How Routing Works
ASP.NET Core's routing mechanism typically involves the following steps:
- Request Reception: The web server receives an incoming HTTP request.
- Route Matching: The routing middleware inspects the request's URL and compares it against a set of defined routes.
- Route Data Extraction: If a match is found, the routing system extracts relevant data from the URL (e.g., controller name, action name, parameters).
- Handler Invocation: The framework invokes the appropriate code handler based on the extracted route data.
Route Templates
Route templates are strings that define the structure of URLs. They can include literal segments and placeholders for variable data.
Literal Segments
These are parts of the URL that must match exactly. For example, in the template products/list, products and list are literal segments.
Placeholders
Placeholders are enclosed in curly braces {} and represent parts of the URL that can vary. They are used to capture dynamic data.
"{controller}/{action}/{id?}"
{controller}: A placeholder for the name of the controller.{action}: A placeholder for the name of the action method.{id?}: A placeholder for an ID. The?makes this parameter optional.
Route Constraints
Route constraints allow you to add rules to route parameters, ensuring that they match specific criteria.
"products/{id:int}" // 'id' must be an integer
"users/{username:minlength(3)}" // 'username' must be at least 3 characters long
"files/{filename:regex(^[a-zA-Z0-9\-_\.]+$)}" // 'filename' must match a specific regex pattern
Configuring Routing
Routing is typically configured in the Program.cs (or Startup.cs) file of your ASP.NET Core application.
Convention-Based Routing
This is the most common approach. It uses conventions to map URLs to controller actions.
using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; 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(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run();
In this example, MapControllerRoute defines a default route. If no specific route matches, it will look for a controller named "Home" and its "Index" action. The {id?} makes the ID parameter optional.
Attribute Routing
Attribute routing allows you to define routes directly on controller actions using attributes. This provides more flexibility and control.
using Microsoft.AspNetCore.Mvc; // In Controllers/ProductsController.cs namespace MvcMovie.Controllers { public class ProductsController : Controller { [Route("api/products")] [HttpGet] public IActionResult GetProducts() { var products = new[] { "Product A", "Product B" }; return Ok(products); } [Route("products/details/{productId:int}")] public IActionResult Details(int productId) { if (productId == 0) { return NotFound(); } return Content($"Details for product ID: {productId}"); } } }
To use attribute routing, you typically need to add app.MapControllers(); in your Program.cs.
Routing for APIs
When building APIs with ASP.NET Core, routing is crucial for defining endpoints. Minimal APIs offer a streamlined way to define routes.
var builder = WebApplication.CreateBuilder(args); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.MapGet("/hello", () => "Hello World!") .WithName("GetHello"); app.MapGet("/items/{id:int}", (int id) => { return Results.Ok($"Item ID: {id}"); }) .WithName("GetItemById"); app.Run();
Best Practices
- Keep URLs Readable: Use clear and descriptive names for your routes.
- Use Consistent Naming: Apply a consistent naming convention for controllers and actions.
- Leverage Optional Parameters: Use optional parameters (
?) for flexibility. - Employ Constraints: Use constraints to validate route parameters and improve robustness.
- Choose the Right Approach: Convention-based routing is good for standard applications, while attribute routing offers more granular control for APIs or complex scenarios.
- Document Your Routes: Especially for APIs, ensure your routes are well-documented.
app.MapControllers(); enabled in your application setup to activate these routes.