簡介
路由是 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})、查詢字符串、請求體等。 - 支持可選參數、默認值和約束。
- 支持路由參數(如
-
中間件集成:
- 通過
UseRouting和UseEndpoints中間件處理路由。 - 支持自定義路由中間件。
- 通過
-
路由約束:
- 限制路由參數(如
int、guid、regex)。 - 提高性能和安全性。
- 限制路由參數(如
-
區域支持(
Areas):- 將控制器分組到不同區域(如
Admin、User)。
- 將控制器分組到不同區域(如
-
動態路由:
- 支持動態生成路由(如基於數據庫配置)。
-
端點路由:
- 統一管理
MVC、Razor Pages和SignalR的路由。
- 統一管理
核心概念
| 名稱 | 説明 |
|---|---|
| 路由模板 | 由文字、參數({id})、可選參數({id?})、默認值、約束組成的字符串 |
| 路由參數 | 路徑中的佔位符,匹配 URL 段並綁定到 Action 方法參數 |
| 路由數據 | 匹配結果的鍵值對集合,可在中間件或 Controller 中通過 RouteData 訪問 |
| 路由約束 | 通過類型(int、guid)、正則(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 APIs 或 Controller 上,可註冊 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.CoreGitHub:https://github.com/dotnet/aspnetcore