博客 / 詳情

返回

C#.NET 路由機制深入解析:從傳統路由到 Endpoint Routing

簡介

路由是 ASP.NET Core 的核心基礎設施,負責將 HTTP 請求映射到對應的處理程序(如控制器方法)。它決定了 URL 如何與應用程序代碼交互,是現代 Web 開發的關鍵組件。

ASP.NET Core 中,路由系統解決了以下問題:

  • URL 映射:將用户友好的 URL 映射到具體的處理程序。
  • 靈活性:支持多種路由配置(如 RESTful 路徑、動態參數)。
  • 性能優化:高效解析請求,快速定位處理邏輯。
  • 可擴展性:通過中間件和自定義路由約束擴展功能。
  • 異步支持:與 async/await 無縫集成,適合現代 Web 應用。

主要功能

  • 基於約定的路由(Convention-based Routing):

    • 使用模板(如 "{controller}/{action}/{id?}")定義路由規則。
    • 適合傳統 MVC 應用。
  • 特性路由(Attribute Routing):

    • 通過 [Route] 特性直接在控制器或動作上定義路由。
    • 適合 RESTful API 和複雜 URL 模式。
  • 參數綁定:

    • 支持路由參數(如 {id})、查詢字符串、請求體等。
    • 支持可選參數、默認值和約束。
  • 中間件集成:

    • 通過 UseRoutingUseEndpoints 中間件處理路由。
    • 支持自定義路由中間件。
  • 路由約束:

    • 限制路由參數(如 int、guid、regex)。
    • 提高性能和安全性。
  • 區域支持(Areas):

    • 將控制器分組到不同區域(如 Admin、User)。
  • 動態路由:

    • 支持動態生成路由(如基於數據庫配置)。
  • 端點路由:

    • 統一管理 MVC、Razor PagesSignalR 的路由。

核心概念

名稱 説明
路由模板 由文字、參數({id})、可選參數({id?})、默認值、約束組成的字符串
路由參數 路徑中的佔位符,匹配 URL 段並綁定到 Action 方法參數
路由數據 匹配結果的鍵值對集合,可在中間件或 Controller 中通過 RouteData 訪問
路由約束 通過類型(intguid)、正則(regex(...))等限制參數匹配規則
默認值 當 URL 中未提供參數時使用的值
終結點(Endpoint) 最終與請求匹配並執行的代碼單元,如 MVC Action、Razor Page、Minimal API

配置方式

啓用 Endpoint Routing

// Program.cs (.NET 6+ Minimal Hosting)
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();   // MVC / API

var app = builder.Build();
app.UseRouting();                     // 啓動路由中間件

app.UseAuthorization();               // 授權、認證等

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();       // 特性路由 + 約定路由
    endpoints.MapRazorPages();        // Razor Pages
    endpoints.MapHub<ChatHub>("/hub"); // SignalR
    // endpoints.MapGet("/ping", () => "pong"); // Minimal API
});
app.Run();

約定路由(Conventional Routing)

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

    endpoints.MapAreaControllerRoute(
        name: "admin",
        areaName: "Admin",
        pattern: "Admin/{controller=Dashboard}/{action=Index}/{id?}");
});
  • pattern:路由模板,包含默認值(=Home)和可選參數(?)。
  • Controller 中可不標註任何特性,直接按約定匹配 URL

特性路由(Attribute Routing)

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    [HttpGet]                     // GET api/products
    public IActionResult GetAll() { … }

    [HttpGet("{id:int}")]        // GET api/products/5,且 id 必須是整數
    public IActionResult Get(int id) { … }

    [HttpPost("batch/{type?}")]   // POST api/products/batch 或 api/products/batch/special
    public IActionResult CreateBatch(string? type) { … }
}
  • [Route]、[HttpGet]、[HttpPost] 等特性定義路由模板、方法限制。
  • 支持在控制器和方法級別混用,覆蓋或疊加。

路由模板詳解

模板語法元素

語法 示例 説明
字面值 api/products 固定匹配的路徑段
參數 {param} {controller} 捕獲值並綁定到參數
可選參數 {id?} {id?} 參數可選
默認值 {id=5} {page=1} 未提供時的默認值
約束 {id:int} {id:min(1)} 限制參數格式
通配符 * {*slug} 捕獲剩餘路徑
命名空間 [Namespace("Admin")] 控制器命名空間約束

路由約束類型

約束 示例 説明
類型約束 {id:int} 必須是整數
範圍約束 {age:range(18,99)} 值在指定範圍內
正則表達式 {ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} 匹配正則模式
必需值 {name:required} 必須提供非空值
自定義約束 {code:validProductCode} 實現 IRouteConstraint 接口

高級特性

動態路由

基於數據庫動態生成路由:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using System.Collections.Generic;
using System.Threading.Tasks;

public class DynamicRouteController : ControllerBase
{
    private readonly Dictionary<string, string> _routes = new()
    {
        { "page1", "Content for Page 1" },
        { "page2", "Content for Page 2" }
    };

    [HttpGet("{key}")]
    public IActionResult GetDynamic(string key)
    {
        if (_routes.TryGetValue(key, out var content))
            return Ok(content);
        return NotFound();
    }
}

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.UseRouting();
app.UseEndpoints(endpoints => endpoints.MapControllers());
app.Run();

多路由規則

[Route("api/[controller]")]
[Route("v2/[controller]")] // 支持多個路由
public class ProductsController : ControllerBase
{
    [HttpGet("all")]
    [HttpGet("list")] // 多個路徑映射同一方法
    public IActionResult ListProducts() { /*...*/ }
}

路由參數轉換

[Route("products/{id:guid}")]
public IActionResult GetProductById(Guid id) { /*...*/ }

[Route("products/{slug:slugify}")] // 自定義 SlugConstraint
public IActionResult GetProductBySlug(string slug) { /*...*/ }

端點元數據(Endpoint Metadata)

通過 WithMetadata(...) 或在特性上添加自定義屬性,可為終結點附加元數據,在中間件中讀取以執行額外邏輯(例如權限校驗、文檔生成)。

路由優先級(Order)

特性路由和約定路由都可設置 Order 屬性,高優先級先匹配:

[Route("special", Order = 1)]
public IActionResult Special() { … }

[Route("{**catchAll}", Order = 100)]
public IActionResult CatchAll() { … }

端點過濾器(Endpoint Filter,.NET 7+)

Minimal APIsController 上,可註冊 Endpoint Filter 以在終結點執行前後插入邏輯,相當於細粒度中間件。

最小 API 路由

app.MapGet("/weather/{day:datetime}", (DateTime day) =>
    $"Weather for {day:yyyy-MM-dd}");
  • 直接在 WebApplication 上映射,既是特性路由也是約定路由的簡化版。
  • 支持參數綁定、依賴注入、請求處理器委託等。

自定義路由約束

實現 IRouteConstraint 接口,註冊到路由選項中,即可在模板裏使用自定義約束

路由診斷與調試

路由信息中間件

app.UseEndpoints(endpoints => { /*...*/ });

// 添加診斷中間件
app.Use(async (context, next) =>
{
    var endpoint = context.GetEndpoint();
    if (endpoint != null)
    {
        Console.WriteLine($"Endpoint: {endpoint.DisplayName}");
        Console.WriteLine($"RoutePattern: {endpoint.Metadata.GetMetadata<RoutePattern>()}");
    }
    await next();
});

優缺點

優點

  • 靈活性:支持約定路由和特性路由,適應多種場景。
  • 性能高:基於端點路由,匹配速度快。
  • 異步友好:支持 async/await,適合現代 Web
  • 可擴展:支持自定義約束、中間件和動態路由。
  • DI 集成:與 ASP.NET Core DI 無縫結合。

缺點

  • 配置複雜:複雜路由規則需仔細設計,避免衝突。
  • 學習曲線:特性路由和約束需要熟悉語法。
  • 調試難度:路由衝突或錯誤需調試工具(如日誌)。
  • 進程內限制:路由配置不跨實例,需結合外部配置。

資源和文檔

  • 官方文檔:

    • Microsoft Learn:https://learn.microsoft.com/en-us/aspnet/core/fundamentals/ro...
    • ASP.NET Core MVC:https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers...
  • NuGet 包:https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.Core
  • GitHub:https://github.com/dotnet/aspnetcore
user avatar mengzyou 頭像 yujiaao 頭像 matrixorigin 頭像 val3344 頭像 u_16213613 頭像 chenchu_6110ed583800c 頭像
6 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.