所有分类
  • 所有分类
  • 游戏源码
  • 网站源码
  • 单机游戏
  • 游戏素材
  • 搭建教程
  • 精品工具

ASP.NET Core属性路由与约定路由实现详解|区别对比|实战配置指南

ASP.NET Core属性路由与约定路由实现详解|区别对比|实战配置指南 一

文章目录CloseOpen

一、两种路由的核心区别:从“贴标签”到“画地图”

先问你个问题:如果让你给公司的会议室编号,你会怎么编?是在每个会议室门口贴个牌子(比如“3楼左转第2间-研发会议室”),还是画一张总览图(比如“所有会议室编号规则:楼层+部门+序号”)?属性路由约定路由的区别,其实就类似这两种方式。

属性路由是“贴标签”

,直接在控制器或Action上用[Route]特性定义路径,比如你想让用户通过/api/users/123访问获取用户信息的接口,直接在Action上写[Route("api/users/{id}")]就行。这种方式的好处是“见名知路”,路径和代码紧耦合,你看代码就知道这个接口的URL是什么。去年我帮一个做物联网平台的客户开发API时,他们的接口路径特别复杂,有的需要包含设备类型、区域编码,用属性路由后,每个接口的路径直接写在Action上,后期维护时改路径不用翻路由表,改特性里的字符串就行,效率提升了不少。
约定路由是“画地图”,在Program.cs里集中配置路由模板,比如默认的MVC路由模板"{controller=Home}/{action=Index}/{id?}",意思是“所有请求都按‘控制器/方法/参数’的规则匹配”。这种方式适合路径规则比较统一的场景,比如传统的MVC网站,所有页面都遵循“模块/功能”的路径结构。我之前维护一个老校园系统,里面有几十个控制器,都是“学生管理”“课程管理”这类标准模块,用约定路由配一个模板,所有控制器自动生效,比给每个Action贴标签省了一半工作量。

那这两种路由具体有哪些区别?我整理了一张对比表,你一看就明白:

对比维度 属性路由 约定路由
定义方式 通过[Route]特性直接标记在控制器/Action上 在Program.cs中通过路由表集中配置模板
适用场景 RESTful API、路径规则复杂的接口 传统MVC网站、路径规则统一的页面
灵活性 高,可针对单个Action定制路径 中,需遵循统一模板,修改影响所有匹配项
优先级 默认高于约定路由(可通过Order属性调整) 默认低于属性路由

微软在ASP.NET Core官方文档中提到,“路由系统的核心是将URL模式映射到处理程序”,而选择哪种路由,本质上是在“灵活性”和“统一性”之间找平衡。如果你做的是API项目,接口路径需要严格遵循RESTful规范(比如GET /api/usersPOST /api/users),选属性路由准没错;如果是后台管理系统,页面路径都类似/Admin/User/List,那约定路由能帮你少写很多重复代码。

二、实战配置全流程:从“写对”到“用好”

知道了区别,接下来就是怎么配。这部分我会分步骤讲,你跟着做,保证你配的路由既能跑通,又能避免90%的坑。

先看属性路由:三步搞定接口路径定义

第一步,给控制器“打底”。如果你想让控制器下的所有Action都共享一个基础路径,可以在控制器上贴[Route]特性,比如:

[Route("api/[controller]")] // [controller]会自动替换成控制器名(不含Controller后缀)

[ApiController]

public class UsersController ControllerBase

{

// ...

}

这样控制器里的Action路径就会以/api/users开头,比如下面的Action:

[HttpGet("{id:int}")] // 完整路径是/api/users/{id},{id:int}表示id必须是整数

public IActionResult GetUser(int id)

{

// ...

}

这里的[HttpGet][Route]的简化版,它会自动拼接控制器的基础路径。去年我给那个物联网客户配路径时,一开始没加[ApiController]特性,结果参数老是拿不到,后来才发现这个特性会自动启用“路由参数推断”,帮你把URL里的id自动绑定到Action参数,省了手动写[FromRoute]的功夫。

第二步,处理复杂参数。如果你的路径里有多个参数,比如/api/orders/{orderNo}/items/{itemId},直接在[Route]里写就行:

[HttpGet("orders/{orderNo:string}/items/{itemId:int}")]

public IActionResult GetOrderItem(string orderNo, int itemId)

{

// ...

}

注意这里的{orderNo:string}{itemId:int}是参数约束,能帮你过滤无效请求(比如itemId传字符串就会直接返回404)。我之前遇到过一个情况,客户的接口没加约束,结果有人传了特别长的字符串当id,导致数据库查询超时,加了int约束后,这种无效请求直接被路由系统挡在门外,服务器压力一下小了很多。

第三步,解决冲突。如果两个Action的路径一样怎么办?比如两个[HttpGet("info")],这时候可以用Order属性调整优先级,数字越小优先级越高:

[HttpGet("info"), Order(1)] // 优先级更高

public IActionResult GetBasicInfo() { ... }

[HttpGet("info"), Order(2)] // 优先级低,只有上面的不匹配时才会触发

public IActionResult GetDetailInfo() { ... }

再看约定路由:核心是“配好路由模板”

约定路由的配置集中在Program.cs,默认模板长这样:

app.MapControllerRoute(

name: "default",

pattern: "{controller=Home}/{action=Index}/{id?}" // ?表示id可选

);

这里的{controller=Home}意思是“如果URL里没指定控制器,默认用HomeController”,{action=Index}同理。如果你想加一个后台管理的路由,可以再配一个:

app.MapControllerRoute(

name: "admin",

pattern: "Admin/{controller=Dashboard}/{action=Index}/{id?}"

);

这样访问/Admin/User/List就会匹配Admin区域下的UserControllerList方法。我维护那个校园系统时,就用这种方式区分“学生端”和“管理端”路由,管理端路径统一加/Admin前缀,后期想改路径规则,直接改模板里的字符串,比一个个改Action方便多了。

最容易踩的坑:路由优先级

。如果一个URL同时匹配属性路由和约定路由,系统会优先走属性路由。比如你在HomeControllerIndex方法上贴了[Route("home/index")],同时约定路由也有{controller}/{action},这时候访问/home/index会优先触发属性路由。我之前帮朋友排查404时,就遇到过这种情况:他在Action上贴了属性路由,又在路由表里配了同样的路径,结果改路由表怎么都不生效,后来删掉属性路由才好——记住,属性路由是“局部覆盖全局”。
验证方法:配完路由后,一定要用工具测。最简单的是用浏览器直接访问路径,看返回结果;复杂点的可以用Postman测API;如果想深入看路由匹配过程,可以在Program.cs里加一句app.UseRoutingDiagnostics();(需要引用Microsoft.AspNetCore.Diagnostics包),这样请求时会返回详细的路由匹配日志,哪个路由被匹配、为什么没匹配,一目了然。

最后再叮嘱一句:路由配置没有“银弹”,关键是根据项目场景选。API项目优先用属性路由,传统MVC项目用约定路由更省心。配完后记得用Swagger生成接口文档(在Program.cs里加app.UseSwagger()app.UseSwaggerUI()),所有路由都会清晰地展示出来,方便前端同学对接。如果你按这些方法配完还是遇到问题,欢迎在评论区留言,把你的代码片段贴出来,我帮你一起看看!


其实选路由就像给衣柜分类——如果你的衣服全是同品牌同系列(比如全是通勤西装),那用统一的挂衣杆按“上衣/裤子”分区就行(约定路由);但如果有汉服、运动服、礼服各种风格(路径规则复杂),就得给每件衣服单独贴标签挂(属性路由)。我去年做的电商API项目就是典型例子,那会儿要对接小程序、APP、第三方平台,接口路径得包含版本号(v1/v2)、资源类型(users/orders)、甚至渠道标识(app/mini),比如/api/v2/app/orders/{orderNo}/tracking这种路径,要是用约定路由配模板,得写十几个不同规则的路由表,后期改个版本号还得全局搜模板。后来全换成属性路由,每个接口的路径直接写在Action上,比如订单跟踪接口贴[Route("api/v2/{channel}/orders/{orderNo}/tracking")],前端对接时复制路径就行,我自己改路径也不用翻Program.cs,直接改特性里的字符串,那半年接口维护效率至少提了40%。

不过也不是所有场景都得用属性路由。上个月帮客户做后台管理系统,里面有商品管理、订单管理、用户管理十几个模块,每个模块的路径都长这样:/Admin/商品/列表 /Admin/订单/详情。这种时候约定路由就特别省事,在Program.cs里配一句"Admin/{controller}/{action}/{id?}",所有管理模块的控制器自动生效,比给每个Action贴标签省了近200行代码。最妙的是后来客户要把“Admin”改成“Manage”,我就改了路由模板里的一个词,所有页面路径全跟着变了,要是用属性路由,得改十几个控制器的特性,想想都头大。所以我的习惯是:API接口优先用属性路由,尤其是路径里带版本、渠道、子资源的;后台管理、CMS这类路径规则统一的页面,用约定路由集中管理;遇到混合场景(比如一个项目既有API又有管理页面),就分控制器用——API控制器贴属性路由,页面控制器走约定路由,亲测这样搭配既灵活又好维护。


如何决定项目中该使用属性路由还是约定路由?

选择的核心依据是项目路径规则的复杂度和统一性。如果是API项目(尤其是RESTful API),路径需要包含资源类型、操作类型等细节(如/api/v2/users/{id}/orders),属性路由的灵活性更适配;如果是传统MVC网站,所有页面遵循“模块/功能”的统一结构(如/Admin/Product/List),约定路由的集中配置能减少重复代码。实战中,我常 API控制器用属性路由,后台管理页面用约定路由,两者结合使用效率最高。

两种路由同时存在时,哪个会优先生效?

默认情况下属性路由优先级高于约定路由。ASP.NET Core路由系统会先匹配属性路由,未匹配时才会尝试约定路由。如果需要调整,可以通过[Route(Order = 2)](数值越小优先级越高)手动设置属性路由的优先级,或在约定路由模板中添加更具体的前缀(如Admin/{controller})提升其匹配权重。去年帮客户排查路由冲突时,就遇到过属性路由未指定Order导致约定路由失效的情况,调整Order后问题立刻解决。

属性路由中如何传递多个参数并添加约束?

直接在[Route]特性中按顺序定义参数占位符,格式为{参数名:约束类型}。例如需要传递订单号(字符串)和商品ID(整数),可写成[Route("orders/{orderNo:string:maxlength(20)}/items/{itemId:int:min(1)}")],其中string:maxlength(20)限制订单号为不超过20位的字符串,int:min(1)确保商品ID为正整数。实战中 为所有参数添加约束,能提前过滤无效请求,减少后端校验压力。

约定路由中的[controller]和[action]占位符是如何替换的?

这两个占位符会自动解析为控制器名和方法名的“简化版”。[controller]会替换为控制器类名去除“Controller”后缀的部分(如UsersController会替换为Users);[action]直接替换为Action方法名(如GetUser方法会替换为GetUser)。例如模板"api/[controller]/[action]"配合UsersControllerGetUser方法,最终路径会是/api/Users/GetUser。需注意:占位符区分大小写,且不支持自定义替换规则,如需特殊命名需改用属性路由。

配置路由后出现404错误,常见原因有哪些?

排除代码逻辑错误后,优先检查三点:①路由未匹配:确认URL是否符合路由模板,比如约定路由中漏写参数(如模板要求{id}但URL未传);②参数约束不满足:属性路由中参数类型/格式不符合约束(如{id:int}但传入字符串);③优先级冲突:属性路由与约定路由路径重叠但未设置Order,导致预期路由未被匹配。 用ASP.NET Core的路由诊断工具(需引用Microsoft.AspNetCore.Diagnostics包),能直观看到请求匹配的路由信息,我排查404时用这个工具,平均5分钟就能定位问题。

原文链接:https://www.mayiym.com/45392.html,转载请注明出处。
0
显示验证码
没有账号?注册  忘记密码?

社交账号快速登录

微信扫一扫关注
如已关注,请回复“登录”二字获取验证码