☰
基于约定的 MVC 路由:使用 IEndpointRouteBuilder.MapControllerRoute 配置 Convention Based Routing
2026/10/15 16:14:47 网站建设 项目流程
  • 示例工程

【免费下载链接】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.

项目地址:https://gitcode.com/gh_mirrors/pr/practical-aspnetcore
点击查看免费下载

约定式路由(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();

可以拆解为三个关键环节:

  1. 注册 MVC 服务:builder.Services.AddControllersWithViews()将 MVC(含视图支持)加入依赖注入容器。这是后续所有MapControllerRoute调用能够生效的前提——端点路由的 MVC 端点构建器依赖这些服务完成控制器发现、动作选择与路由匹配。
  2. 声明路由:app.MapControllerRoute是IEndpointRouteBuilder上的扩展方法,它将一条约定式路由注册为一个命名端点(named endpoint)。
  3. 运行: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的注册顺序决定了匹配优先级:路由表按注册顺序依次尝试,先注册的路由优先命中。在本示例中:

  1. 请求/Admin→ 命中第一条命名路由"Admin",交由AdminController.Index处理(返回"Admin Page"纯文本)。
  2. 请求/About→ 命中第二条命名路由"About",交由HomeController.About处理(返回"About Page"纯文本)。
  3. 请求/、/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.

项目地址:https://gitcode.com/gh_mirrors/pr/practical-aspnetcore
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询