MS Net Routing
Routing is a core concept in the MS Net framework. It determines how incoming HTTP requests are mapped to the appropriate handler code within your application. This document explains the principles of routing and how to configure it effectively.
Core Concepts
MS Net uses a convention-based and explicit routing system. You define routes that match specific URL patterns and HTTP methods, and then associate them with controller actions or other request handlers.
Route Definitions
Routes are typically defined in the application's startup configuration, often in a file like Startup.cs
or Program.cs
.
// Example in Startup.cs (older .NET Core versions)
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context => await context.Response.WriteAsync("Hello World!"));
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
// Example in Program.cs (newer .NET versions)
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
URL Patterns
Route patterns are strings that define the structure of URLs to match. They can include:
- Literal segments: e.g.,
/api/products
- Parameter segments: e.g.,
/users/{userId}
, where{userId}
is a placeholder that will be populated with a value from the URL. - Optional segments: e.g.,
/items/{itemId}?
, where the?
makes the segment optional. - Defaults: You can specify default values for segments.
HTTP Methods
You can constrain routes to specific HTTP methods like GET, POST, PUT, DELETE, etc.
endpoints.MapPost("/api/users", async context => { /* ... */ });
endpoints.MapPut("/api/products/{id}", async context => { /* ... */ });
Route Constraints
Route constraints allow you to further refine which requests a route will match. This is useful for ensuring parameters meet specific criteria.
endpoints.MapGet("/products/{productId}", async context =>
{
var productId = context.Request.RouteValues["productId"];
await context.Response.WriteAsync($"Product ID: {productId}");
}).Add(static routeBuilder =>
{
routeBuilder.WithMetadata(new RouteParameterTransformerMetadata(new SlugifyParameterTransformer()));
});
endpoints.MapGet("/articles/{year:int}/{month:regex(^\\d{{2}}$)}/{day:range(1,31)}", async context =>
{
var year = context.Request.RouteValues["year"];
var month = context.Request.RouteValues["month"];
var day = context.Request.RouteValues["day"];
await context.Response.WriteAsync($"Date: {year}-{month}-{day}");
});
Common constraints include:
int
: Matches an integer.decimal
: Matches a decimal number.guid
: Matches a GUID.alpha
: Matches alphabetic characters.regex(pattern)
: Matches a custom regular expression.length(min, max)
: Matches a string of a specific length.range(min, max)
: Matches a number within a specified range.
Route Parameters
Values captured from the URL by route parameters can be accessed from the RouteValues
collection on the HttpContext
.
Accessing Route Values
In an endpoint handler:
var userId = context.Request.RouteValues["userId"];
In a Controller action:
public IActionResult GetUser(string userId)
{
// userId will be automatically populated
return Ok($"User ID: {userId}");
}
Important Note
The order in which you define your routes matters. The framework will try to match routes in the order they are registered. More specific routes should generally be defined before more general ones.
Routing with Controllers
When using controllers, the routing system automatically maps URLs to controller actions based on conventions or explicit route attributes.
// In a controller file (e.g., ProductsController.cs)
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet] // Matches GET /api/products
public IActionResult GetAllProducts() { /* ... */ }
[HttpGet("{id}")] // Matches GET /api/products/{id}
public IActionResult GetProductById(int id) { /* ... */ }
[HttpPost] // Matches POST /api/products
public IActionResult CreateProduct([FromBody] Product newProduct) { /* ... */ }
}
The [Route]
attribute defines the base route for the controller, and method attributes like [HttpGet]
, [HttpPost]
, etc., define specific endpoints.
Custom Route Constraints and Transformers
For advanced scenarios, you can create custom route constraints or transformers to implement unique routing logic.
Tip
Consider using the built-in constraints for common validation needs before resorting to custom solutions.