.NET Core从2.1升级到3.1/5后自定义路由匹配抛出ArgumentOutOfRangeException
问题根因
.NET Core 3.0+ 更换了全新的DFA路由匹配引擎,在处理同一路由段内包含多个参数+固定字面量的复杂路由场景时,匹配逻辑和2.1版本的旧路由引擎存在差异:引擎会按路由注册顺序依次尝试匹配所有符合路径层级的路由,你当前的场景中,访问/MyPath/my-slug/s1时引擎会先尝试匹配先注册的MyCustomRoute1的第三段规则m{id1}s{id2},解析过程中计算参数长度出错,直接抛出ArgumentOutOfRangeException异常,没有走到后续的MyCustomRoute2匹配逻辑。
解决方案
可根据你的项目情况选择以下任意一种方案:
- 方案1(最简便,无侵入):调整两条路由的注册顺序,将规则更精准、段长度更短的
MyCustomRoute2放在MyCustomRoute1之前注册。路由系统按注册顺序优先匹配,访问s1结尾的路径时会先命中MyCustomRoute2,不会触发MyCustomRoute1的解析逻辑,即可正常运行。
修改后的注册代码示例:// 先注册更精准的短段路由 endpoints.MapControllerRoute( name: "MyCustomRoute2", pattern: "MyPath/{slug}/s{id1}", defaults: new { controller = "home", action = "Index" }, constraints: new { slug = "[a-z-]+", id1 = "[0-9]+" }); // 再注册长段路由 endpoints.MapControllerRoute( name: "MyCustomRoute1", pattern: "MyPath/{slug}/m{id1}s{id2}", defaults: new { controller = "home", action = "Index" }, constraints: new { slug = "[a-z-]+", id1 = "[0-9]+", id2 = "[0-9]+" }); - 方案2(兼容旧逻辑):如果不想改动现有路由注册顺序,可以回退到.NET Core 2.1的旧路由系统,在
Startup.cs的ConfigureServices方法中添加如下配置即可:
注意该方案为兼容方案,不建议长期使用,旧路由系统后续版本可能会被移除。services.AddControllersWithViews() .AddMvcOptions(options => options.EnableEndpointRouting = false); - 方案3(更稳定):改用属性路由配置规则,直接在对应的Controller Action上标注路由属性,属性路由优先级高于全局注册的路由,不会出现匹配顺序问题:
配置后删除Startup中对应的两条全局路由注册即可。public class HomeController : Controller { [Route("MyPath/{slug:regex([a-z-]+)}/m{id1:regex([0-9]+)}s{id2:regex([0-9]+)}", Name = "MyCustomRoute1")] [Route("MyPath/{slug:regex([a-z-]+)}/s{id1:regex([0-9]+)}", Name = "MyCustomRoute2")] public IActionResult Index(string slug, int id1, int? id2) { // 业务逻辑 } }
内容的提问来源于stack exchange,提问作者Beedjees
相关产品推荐
相关产品推荐

