- 示例工程
【免费下载链接】practical-aspnetcore
Practical samples of ASP.NET Core 11, 10, 9, 8.0, 7.0, 6.0, 5.0, 3.1, 2.2, and 2.1,projects you can use. Readme contains explanations on all projects.
约定式路由(Convention Based Routing)是 ASP.NET Core MVC 中最经典的路由组织方式:它通过一段集中定义的 URL 模板(如{controller}/{action}/{id})来统一推导"哪个控制器、哪个动作方法"处理请求,而无需在每个控制器或 Action 上逐个书写[Route]特性。在 ASP.NET Core 端点路由(Endpoint Routing)时代,这一能力由扩展方法IEndpointRouteBuilder.MapControllerRoute提供。本指南以practical-aspnetcore仓库中的 new-routing-20 示例项目为蓝本,完整讲解如何用MapControllerRoute注册带默认值(defaults)的命名路由、如何叠加通用默认路由{controller=Home}/{action=Index}/{id?},以及约定式路由与属性路由、区域路由(MapAreaControllerRoute)之间的分工与取舍。读完本文,你将能够在自己的 ASP.NET Core 项目中独立配置 MVC 约定式路由,并理解其背后的匹配顺序与链路。
示例项目结构一览
示例位于 projects/endpoint-routing/new-routing-20,是一个面向net10.0的极简 MVC 项目,目录结构如下:
projects/endpoint-routing/new-routing-20/ ├── Controllers/ │ ├── AdminController.cs │ └── HomeController.cs ├── Views/ │ └── Home/ │ └── Index.cshtml ├── Program.cs ├── new-routing-20.csproj └── README.md项目文件 new-routing-20.csproj 只声明了 Web SDK 与目标框架,没有引入任何额外 NuGet 包——MVC 框架本身随Microsoft.NET.Sdk.Web提供:
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net10.0</TargetFramework> <ImplicitUsings>true</ImplicitUsings> <LangVersion>preview</LangVersion> </PropertyGroup> </Project>其中ImplicitUsings启用了隐式 using,因此 Program.cs 无需显式using Microsoft.AspNetCore.Builder即可直接调用MapControllerRoute。
核心思路:MapControllerRoute 与约定式路由
本示例在 Program.cs 中展示了约定式路由的标准三步流程:
var builder = WebApplication.CreateBuilder(); builder.Services.AddControllersWithViews(); var app = builder.Build(); app.MapControllerRoute("Admin", "Admin", new { Controller = "Admin", Action = "Index" }); app.MapControllerRoute("About", "About", new { Controller = "Home", Action = "About" }); app.MapControllerRoute("Default", "{controller=Home}/{action=Index}/{id?}"); app.Run();可以拆解为三个关键环节:
- 注册 MVC 服务:
builder.Services.AddControllersWithViews()将 MVC(含视图支持)加入依赖注入容器。这是后续所有MapControllerRoute调用能够生效的前提——端点路由的 MVC 端点构建器依赖这些服务完成控制器发现、动作选择与路由匹配。 - 声明路由:
app.MapControllerRoute是IEndpointRouteBuilder上的扩展方法,它将一条约定式路由注册为一个命名端点(named endpoint)。 - 运行:
app.Run()启动应用,端点路由中间件随后会按注册顺序对入站请求执行匹配。
提示:
MapControllerRoute与更古老的IApplicationBuilder.UseMvc不同,它不再"接管"整个中间件管道,而是仅仅在端点路由体系中追加一个端点。这也正是"Endpoint Routing 时代"的约定式路由与传统 MVC 5/ASP.NET Core 2.x 时代UseMvcWithDefaultRoute最本质的区别。
三个参数:name、pattern 与 defaults
MapControllerRoute最常用的重载签名可以理解为:
MapControllerRoute(name, pattern, defaults)以示例中的第一条路由为例:
app.MapControllerRoute("Admin", "Admin", new { Controller = "Admin", Action = "Index" });name(路由名):这里为"Admin"。命名路由的价值在于可以被 URL 生成机制引用——例如在 Razor 视图中使用 Tag Helper、或通过IUrlHelper.RouteUrl/LinkGenerator按名字生成链接。路由名在同一应用中必须唯一,否则注册时会抛出ArgumentException。pattern(URL 模板):这里为字面量"Admin",表示请求路径必须是/Admin才会命中这条路由。defaults(默认值):通过匿名对象new { Controller = "Admin", Action = "Index" }提供。当请求命中/Admin且 URL 中没有携带controller/action段时,路由系统会用这两个默认值补全路由值,从而定位到AdminController.Index。
同理,第二条路由将字面量路径/About映射到HomeController.About:
app.MapControllerRoute("About", "About", new { Controller = "Home", Action = "About" });这种"用字面量模板 + 默认值"的组合,非常适合为需要"固定、好记、对外稳定"的 URL(如管理后台、关于页)建立别名式路由,而无需在这些 Controller 的 Action 上书写[Route]特性。
通用默认路由 {controller=Home}/{action=Index}/{id?}
第三段路由是经典的 MVC 默认路由:
app.MapControllerRoute("Default", "{controller=Home}/{action=Index}/{id?}");它把三件事压缩在一个模板里:
| 模板片段 | 含义 | 说明 |
|---|---|---|
{controller=Home} | 可选的控制器段,缺省时使用Home | 访问/时会映射到HomeController |
{action=Index} | 可选的 Action 段,缺省时使用Index | 与上一条配合,/命中HomeController.Index |
{id?} | 可选的id参数段 | 带?表示可为空,如/Home/Index/42会把42绑定到 Action 的id参数 |
因此该模板实际上等价于:/Home/Index、/Home、/都能被匹配,并分别补全缺失的默认值。仓库中 new-routing-3 演示了这条默认路由的"快捷写法"——直接调用app.MapDefaultControllerRoute(),其内部注册的正是同样的{controller=Home}/{action=Index}/{id?}模板。
注意默认值语法:模板内用
{controller=Home}(等号)表示"缺省值",而id后加?表示"可选段",二者含义不同——前者是值级默认,后者是段级可选。这是约定式路由模板最容易混淆的地方之一。
路由匹配顺序:先注册的优先
MapControllerRoute的注册顺序决定了匹配优先级:路由表按注册顺序依次尝试,先注册的路由优先命中。在本示例中:
- 请求
/Admin→ 命中第一条命名路由"Admin",交由AdminController.Index处理(返回"Admin Page"纯文本)。 - 请求
/About→ 命中第二条命名路由"About",交由HomeController.About处理(返回"About Page"纯文本)。 - 请求
/、/Home、/Home/Index→ 命中第三条默认路由,交给HomeController.Index,由 Index.cshtml 渲染页面。
Index.cshtml 中给出了两条可直接点击验证的链接:
<h1>Home Page - Convention based Routing</h1> Use IEndpointRouteBuilder.MapControllerRoute to configure convention based routing. <ul> <li><a href="/Admin">/Admin</a></li> <li><a href="/About">/About</a></li> </ul>页面标题与列表本身即是对 README 主题的运行时验证——浏览器访问/看到该页面,再点击/Admin与/About,即可观察到路由分别被分发到两个不同控制器。
对应地,Controllers/HomeController.cs 与 Controllers/AdminController.cs 的实现非常直观:
public class HomeController : Controller { public IActionResult Index() => View(); public IActionResult About() => Content("About Page"); } public class AdminController : Controller { public IActionResult Index() => Content("Admin Page"); }注意:两个控制器都没有写任何[Route]特性,完全依赖约定式路由完成寻址——这正是"约定式路由"与"属性路由"的分水岭。
约定式路由 vs 属性路由 vs 区域路由
与属性路由(Attribute Routing)的分工
IEndpointRouteBuilder上还提供了MapControllers(),用于启用属性路由。仓库中的 new-routing-2 展示了对照场景:它只调用app.MapControllers(),并依靠类上的[Route("")]特性完成路由,README 明确注明"本示例不启用约定式路由"。
两者可以共存于同一应用:MapControllerRoute负责约定式路由,[Route]/[HttpGet]特性负责属性路由,二者的端点会同时进入端点路由表。一般而言,约定式路由适合"URL 结构统一、由模板驱动"的站点型应用;属性路由适合"URL 形态灵活、需要精细化控制"的 API 型应用。
与区域路由(Area Routing)的关系
约定式路由的"区域变体"由MapAreaControllerRoute提供。仓库中的 new-routing-16 展示了如何同时注册Admin与Customer两个区域:
app.MapAreaControllerRoute("AdminArea", "Admin", "Admin/{controller=Home}/{action=Index}/{id?}"); app.MapAreaControllerRoute("CustomerArea", "Customer", "Customer/{controller=Home}/{action=Index}/{id?}"); app.MapDefaultControllerRoute();其区域名("Admin"、"Customer")必须与控制器上[Area()]特性声明的区域名一致。MapControllerRoute与MapAreaControllerRoute同属约定式路由家族,前者面向普通控制器,后者面向带区域的控制器。
运行与验证
在仓库根目录下执行以下命令即可运行本示例:
cd projects/endpoint-routing/new-routing-20 dotnet run(也可先dotnet restore再运行;该项目不依赖外部包,restore 过程很快。)
启动后按顺序验证:
| 访问路径 | 预期结果 |
|---|---|
/ | 渲染 Index.cshtml 首页 |
/Admin | 输出纯文本Admin Page(来自 AdminController.Index) |
/About | 输出纯文本About Page(来自 HomeController.About) |
这三条结果正好分别对应Program.cs中注册的三条路由,是"命名路由 + 默认值 + 通用模板"三种用法的可运行佐证。
小结
IEndpointRouteBuilder.MapControllerRoute是 ASP.NET Core 端点路由体系中配置 MVC 约定式路由的标准入口。通过 new-routing-20 示例可以看到,仅凭三段代码即可实现:为/Admin、/About建立带默认值的命名路由,并保留{controller=Home}/{action=Index}/{id?}通用回退。掌握name/pattern/defaults三个参数、理解模板默认值与可选段的语法差异、遵循"先注册先匹配"的顺序原则,就能在真实项目中自如地组织 MVC 的 URL 空间;当需要为控制器补充更灵活或分区域的寻址时,再结合 MapControllers 与 MapAreaControllerRoute 即可形成完整的路由体系。
相关示例索引可参见 endpoint-routing 目录总览,其中收录了 30 余个端点路由场景(Razor Pages 映射、默认路由、RequestDelegate、Fallback、主机匹配、动态路由等),可作为路由主题的延伸阅读清单。
- 示例工程
【免费下载链接】practical-aspnetcore
Practical samples of ASP.NET Core 11, 10, 9, 8.0, 7.0, 6.0, 5.0, 3.1, 2.2, and 2.1,projects you can use. Readme contains explanations on all projects.
相关推荐
semantic-router 基于 MCP 的自定义路由分类指南(MCP Based Routing)
semantic router 基于 MCP 的自定义路由分类指南(MCP Based Routing) 本指南讲解如何在 semantic router 中使
后端API网关模型推理服务AI Agent使用 TanStack Router CLI 安装并配置文件路由(File-based Routing)
使用 TanStack Router CLI 安装并配置文件路由(File based Routing) 本文面向希望在不使用 Vite/Rspack 等受支持
前端路由SSRGBrain Brain Routing 约定全解:基于 Brain × Source 双轴的路由决策指南
GBrain Brain Routing 约定全解:基于 Brain × Source 双轴的路由决策指南 本文是 GBrain(Garry's Opinion
人工智能RAGAgent 记忆MCP 服务知识管理
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考