使用*CatchAll后路由失效?Asp.Net MVC区域路由跳转异常排查
这个问题的核心在于路由匹配的优先级逻辑和通配符参数的语法错误,咱们一步步拆解:
1. 路由匹配顺序与无约束路由的干扰
ASP.NET MVC的路由系统在生成URL时,是按照你定义路由的顺序依次尝试匹配参数的。你把Admin区域路由放在了前面,这本身没问题,但第二个路由(SimplifyAsdreaAdmin)有两个致命问题:
- 它没有添加
area相关的约束或默认值,路由系统无法区分它是用于非区域请求的; - 你写的
/*Catchall语法错误,导致路由系统对这个模板的解析出现偏差,反而让它“兼容”了带area参数的请求——当你生成Admin区域的URL时,路由系统错误地认为第二个路由可以匹配(把area=Admin当成了查询参数而不是路由段),跳过了第一个专门处理区域的路由。
2. 通配符参数的写法错误
ASP.NET MVC中,通配符参数的正确写法是{*catchall}——必须用大括号包裹,并且以*开头,这样才能匹配URL中剩余的所有路径部分。你当前的/*Catchall会被路由系统解析为一个字面量的路径段(也就是必须包含/Catchall这个固定部分),这不仅起不到“捕获所有”的作用,还会干扰正常的路由匹配逻辑。
解决方法
你只需要做两个调整,就能让路由恢复正常:
第一步:修正通配符的写法
把第二个路由里的/*Catchall改成{*catchall},让它正确地作为通配符参数使用:
routes.MapRoute( name: "SimplifyAsdreaAdmin", template: "{controller=home}/{action=index}/{id:int?}/{*catchall}" );
第二步:给非区域路由添加area约束
为了让路由系统明确这个路由只处理没有指定区域的请求,你需要添加area=""的默认值或约束,这样生成区域URL时,路由系统会直接跳过这个路由,匹配前面的Admin区域路由:
routes.MapRoute( name: "SimplifyAsdreaAdmin", template: "{controller=home}/{action=index}/{id:int?}/{*catchall}", defaults: new { area = "" } // 明确指定该路由对应无区域的请求 );
或者用约束的方式:
routes.MapRoute( name: "SimplifyAsdreaAdmin", template: "{controller=home}/{action=index}/{id:int?}/{*catchall}", constraints: new { area = "" } );
这样调整后,当你生成Admin区域的URL时,路由系统会因为area=Admin不满足第二个路由的area=""约束,自动去匹配第一个AdminArea路由,生成预期的区域路径,而不是带查询参数的URL。
至于移除*CatchAll后正常的原因:没有通配符干扰时,第二个路由的模板是明确的(没有area路由段),路由系统会判断它无法匹配带area参数的请求,从而正确选择第一个区域路由。
内容的提问来源于stack exchange,提问作者farshid jahanmanesh

