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:

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:

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.