创建测试工程

分别在vs2013和vs2015中创建mvc项目,并创建First、Second、Three三个Area,每个Area下面创建一个HomeController和Index视图。修改RouteConfig.cs中的路由注册方法,添加命名空间

       public static void RegisterRoutes(RouteCollection routes){routes.IgnoreRoute("{resource}.axd/{*pathInfo}");routes.MapRoute(name: "Default",url: "{controller}/{action}/{id}",defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },    namespaces: new[] { "RouteDebuggerMvc5Demo.Controllers" });}

修改三个Area的路由注册方法,添加命名空间:

  public class FirstAreaRegistration : AreaRegistration {public override string AreaName {get {return "First";}}public override void RegisterArea(AreaRegistrationContext context) {context.MapRoute("First_default","First/{controller}/{action}/{id}",new { action = "Index", id = UrlParameter.Optional },        namespaces: new[] { "RouteDebuggerMvc5Demo.Areas.First.Controllers" });}}

使用nuget添加RouteDebugger引用,在Web.config中配置启用 <add key="RouteDebugger:Enabled" value="true" />,运行起来:

VS2013中升序

Matches Current Request Url Defaults Constraints DataTokens
False First/{controller}/{action}/{id} action = Index, id = UrlParameter.Optional (empty) Namespaces = RouteDebuggerMvc5Demo.Areas.First.Controllers, area = First, UseNamespaceFallback = False
False Second/{controller}/{action}/{id} action = Index, id = UrlParameter.Optional (empty) Namespaces = RouteDebuggerMvc5Demo.Areas.Second.Controllers, area = Second, UseNamespaceFallback = False
False Three/{controller}/{action}/{id} action = Index, id = UrlParameter.Optional (empty) Namespaces = RouteDebuggerMvc5Demo.Areas.Three.Controllers, area = Three, UseNamespaceFallback = False
False {resource}.axd/{*pathInfo} (null) (empty) (null)
True {controller}/{action}/{id} controller = Home, action = Index, id = UrlParameter.Optional (empty) Namespaces = RouteDebuggerMvc5Demo.Controllers
True {*catchall} (null) (null) (null)

VS2015中降序

All Routes
Matches Current Request Url Defaults Constraints DataTokens
False Three/{controller}/{action}/{id} action = Index, id = UrlParameter.Optional (empty) Namespaces = RouteDebuggerDemo.Areas.Three.Controllers, RouteDebuggerDemo, area = Three, UseNamespaceFallback = False
False Second/{controller}/{action}/{id} action = Index, id = UrlParameter.Optional (empty) Namespaces = RouteDebuggerDemo.Areas.Second.Controllers, RouteDebuggerDemo, area = Second, UseNamespaceFallback = False
False First/{controller}/{action}/{id} action = Index, id = UrlParameter.Optional (empty) Namespaces = RouteDebuggerDemo.Areas.First.Controllers, RouteDebuggerDemo, area = First, UseNamespaceFallback = False
False {resource}.axd/{*pathInfo} (null) (empty) (null)
True {controller}/{action}/{id} controller = Home, action = Index, id = UrlParameter.Optional (empty) Namespaces = RouteDebuggerDemo.Controllers, RouteDebuggerDemo
True {*catchall} (null) (null) (null)

如果在VS2013中的某个路由注册有问题,一直没有显现出来,升级到VS2015后出现了404就有可能是路由匹配顺序导致的。问题参考:Why did the order of Areas in RegisterAllAreas change with Visual Studio 2015?

手动修改路由顺序

默认在 *.csproj文件中的路由顺序是

<Compile Include="Areas\First\Controllers\HomeController.cs" />
<Compile Include="Areas\First\FirstAreaRegistration.cs" />
<Compile Include="Areas\Second\Controllers\HomeController.cs" />
<Compile Include="Areas\Second\SecondAreaRegistration.cs" />
<Compile Include="Areas\Three\Controllers\HomeController.cs" />
<Compile Include="Areas\Three\ThreeAreaRegistration.cs" />

修改成

<Compile Include="Areas\First\Controllers\HomeController.cs" />
<Compile Include="Areas\First\FirstAreaRegistration.cs" />
<Compile Include="Areas\Three\Controllers\HomeController.cs" />
<Compile Include="Areas\Three\ThreeAreaRegistration.cs" />
<Compile Include="Areas\Second\Controllers\HomeController.cs" />
<Compile Include="Areas\Second\SecondAreaRegistration.cs" />

重新访问页面查看路由,顺序已经改变了(对比上面VS2015里的顺序),可以通过这种方法把最常用的路由调到最前面,提高匹配速度。经测试添加新的Area后,调整的路由顺序不会变回去,可以放心使用。

参考链接:.Net MVC Area Registration Sequence

RouteDebugger 简介

作者地址:ASP.NET Routing Debugger,代码结构图如下:

程序集属性[assembly: PreApplicationStartMethod(typeof(PreApplicationStart), "Start")] 使PreApplicationStart的Start方法在Application_Start方法之前执行,

public static void Start(){bool flag = Convert.ToBoolean(ConfigurationManager.AppSettings["RouteDebugger:Enabled"]);if (flag){DynamicModuleUtility.RegisterModule(typeof(RouteDebuggerHttpModule));}}

最后处理请求的是DebugHttpHandler里的ProcessRequest方法把匹配的路由信息获取出来,代码如下:

  //处理请求public void ProcessRequest(HttpContext context){HttpRequest request = context.Request;if (!this.IsRoutedRequest(request) || context.Response.ContentType == null || !context.Response.ContentType.Equals("text/html", StringComparison.OrdinalIgnoreCase)){return;}string text = string.Empty;RequestContext requestContext = request.RequestContext;if (request.QueryString.Count > 0){RouteValueDictionary routeValueDictionary = new RouteValueDictionary();foreach (string text2 in request.QueryString.Keys){if (text2 != null){routeValueDictionary.Add(text2, request.QueryString[text2]);}}VirtualPathData virtualPath = RouteTable.Routes.GetVirtualPath(requestContext, routeValueDictionary);if (virtualPath != null){text = "<p><label style=\"font-weight: bold; font-size: 1.1em;\">Generated URL</label>: ";text = text + "<strong style=\"color: #00a;\">" + virtualPath.VirtualPath + "</strong>";Route route = virtualPath.Route as Route;if (route != null){text = text + " using the route \"" + route.Url + "\"</p>";}}}string text3 = string.Empty;RouteData routeData = requestContext.RouteData;RouteValueDictionary values = routeData.Values;RouteBase route2 = routeData.Route;string text4 = string.Empty;using (RouteTable.Routes.GetReadLock()){foreach (RouteBase current in RouteTable.Routes){//查询请求与路由是否匹配bool flag = current.GetRouteData(requestContext.HttpContext) != null;string isMatchRequest = string.Format("<span{0}>{1}</span>", DebugHttpHandler.BoolStyle(flag), flag);string url = "n/a";string defaults = "n/a";string constraints = "n/a";string dataTokens = "n/a";Route route3 = this.CastRoute(current);if (route3 != null){url = route3.Url;defaults = DebugHttpHandler.FormatDictionary(route3.Defaults);constraints = DebugHttpHandler.FormatDictionary(route3.Constraints);dataTokens = DebugHttpHandler.FormatDictionary(route3.DataTokens);}text4 += string.Format("<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td></tr>", new object[]{isMatchRequest,url,defaults,constraints,dataTokens});}}string text10 = "n/a";string text11 = "";if (!(route2 is DebugRoute)){foreach (string current2 in values.Keys){text3 += string.Format("\t<tr><td>{0}</td><td>{1}&nbsp;</td></tr>", current2, values[current2]);}foreach (string current3 in routeData.DataTokens.Keys){text11 += string.Format("\t<tr><td>{0}</td><td>{1}&nbsp;</td></tr>", current3, routeData.DataTokens[current3]);}Route route4 = route2 as Route;if (route4 != null){text10 = route4.Url;}}else{text10 = string.Format("<strong{0}>NO MATCH!</strong>", DebugHttpHandler.BoolStyle(false));}text3 = "text3";text10 = "text10";text4 = "text4";text11 = "text11";text = "text";context.Response.Write(string.Format("<html>\r\n<div id=\"haackroutedebugger\" style=\"background-color: #fff; padding-bottom: 10px;\">\r\n    <style>\r\n        #haackroutedebugger, #haackroutedebugger td, #haackroutedebugger th {{background-color: #fff; font-family: verdana, helvetica, san-serif; font-size: small;}}\r\n        #haackroutedebugger tr.header td, #haackroutedebugger tr.header th {{background-color: #ffc;}}\r\n    </style>\r\n    <hr style=\"width: 100%; border: solid 1px #000; margin:0; padding:0;\" />\r\n    <h1 style=\"margin: 0; padding: 4px; border-bottom: solid 1px #bbb; padding-left: 10px; font-size: 1.2em; background-color: #ffc;\">Route Debugger</h1>\r\n    <div id=\"main\" style=\"margin-top:0; padding: 0 10px;\">\r\n        <p style=\"font-size: .9em; padding-top:0\">\r\n            Type in a url in the address bar to see which defined routes match it. \r\n            A {{*catchall}} route is added to the list of routes automatically in \r\n            case none of your routes match.\r\n        </p>\r\n        <p style=\"font-size: .9em;\">\r\n            To generate URLs using routing, supply route values via the query string. example: <code>http://localhost:14230/?id=123</code>\r\n        </p>\r\n        <p><label style=\"font-weight: bold; font-size: 1.1em;\">Matched Route</label>: {1}</p>\r\n        {5}\r\n        <div style=\"float: left;\">\r\n            <table border=\"1\" cellpadding=\"3\" cellspacing=\"0\" width=\"300\">\r\n                <caption style=\"font-weight: bold;\">Route Data</caption>\r\n                <tr class=\"header\"><th>Key</th><th>Value</th></tr>\r\n                {0}\r\n            </table>\r\n        </div>\r\n        <div style=\"float: left; margin-left: 10px;\">\r\n            <table border=\"1\" cellpadding=\"3\" cellspacing=\"0\" width=\"300\">\r\n                <caption style=\"font-weight: bold;\">Data Tokens</caption>\r\n                <tr class=\"header\"><th>Key</th><th>Value</th></tr>\r\n                {4}\r\n            </table>\r\n        </div>\r\n        <hr style=\"clear: both;\" />\r\n        <table border=\"1\" cellpadding=\"3\" cellspacing=\"0\">\r\n            <caption style=\"font-weight: bold;\">All Routes</caption>\r\n            <tr class=\"header\">\r\n                <th>Matches Current Request</th>\r\n                <th>Url</th>\r\n                <th>Defaults</th>\r\n                <th>Constraints</th>\r\n                <th>DataTokens</th>\r\n            </tr>\r\n            {2}\r\n        </table>\r\n        <hr />\r\n        <h3>Current Request Info</h3>\r\n        <p>\r\n            AppRelativeCurrentExecutionFilePath is the portion of the request that Routing acts on.\r\n        </p>\r\n        <p><strong>AppRelativeCurrentExecutionFilePath</strong>: {3}</p>\r\n    </div>\r\n</div>", new object[]{text3,text10,text4,request.AppRelativeCurrentExecutionFilePath,text11,text}));}

注:RouteDebugger的源码是通过ILSpy反编译的。

结束语

抽出时间去验证路由顺序是因为两个错误引起的:

1.升级vs2013的mvc4解决方案到vs2015后所有的Area路由失效,返回404错误。以为是vs2015对mvc4的支持不够(刚出来是对mvc4是有点问题),就撤销升级返回vs2013了。

2.在vs2013中添加了一个新的Area,排在了以前的所有路由之后,出现404错误。通过RouteDebugger发现是路由的顺序问题,所以想到上面那个问题应该也是顺序问题,不应该是vs2015的缺陷。

希望这篇文章可以帮助你避免遇到同样的问题,觉着有用就推荐一下吧

转载于:https://www.cnblogs.com/zeroes/p/vs2015-arearoute-orderbyname-desc.html

VS2013和VS2015中MVC 区域路由匹配顺序相反相关推荐

  1. VS2013、VS2015中,新建项目没有看到解决方案的问题(已解决)

    VS2013.VS2015中,新建项目没有看到解决方案的问题(已解决) 参考文章: (1)VS2013.VS2015中,新建项目没有看到解决方案的问题(已解决) (2)https://www.cnbl ...

  2. .net core mvc 区域路由设置(配置)

    写博客原因:添加了区域(用作后台)后,报错: An unhandled exception occurred while processing the request. AmbiguousAction ...

  3. linux 网络 路由,网络路由的顺序在Linux中是否重要?

    根据定义,输入路线的顺序并不重要.这是由于应该如何应用路由:更具体的路由优先于更通用的路由. 假设您有两条路线: >第一个用于172.16.0.0/16网络,通过网关192.168.1.1 &g ...

  4. MVC源码分析 - 路由匹配

    上一篇 说到了路由事件注册以及路由表的生成, 前面 也解析到了, 管道事件的建立, 那么接下来, 肯定就是要调用执行这些事件了, 这些就不表了, 我已经得到我想要的部分了, 接下来, 在执行这些管道事 ...

  5. django中路由匹配规则

    1.定义 指url与后端视图之间的一一映射关系 2.添加路由以及匹配规则 1)需要在全局路由文件中(url.py),urlpatterns列表中添加路由条目 2)urlpatterns是固定的,是列表 ...

  6. ASP.NET MVC 自定义路由中几个需要注意的小细节

    本文主要记录在ASP.NET MVC自定义路由时,一个需要注意的参数设置小细节. 举例来说,就是在访问 http://localhost/Home/About/arg1/arg2/arg3 这样的自定 ...

  7. MVC简单实现插件Demo-从底层理解MVC路由匹配浏览器请求的URL

    今天实现了在mvc平台下自定义插件,虽然功能比较简单,但是通过对反射的运用,更加明白了为什么我们在浏览器上输入友好的url时,mvc会智能的帮我们找到我们想要查找的页面呢?mvc在底层又是怎样实现的呢 ...

  8. mvc 路由 .html 404,部署ASP.NET的MVC网站到IIS 6.0中,发现路由无法解析而出现404错误解决方案...

    部署ASP.NET MVC应用到IIS 6总是会引起混乱在第一.你已经编码在Visual Studio 2008中,看到你可爱干净的URL中内置的Web服务器很好地工作,你坚持了一些代码的Window ...

  9. php的mvc中的ajax请求参数为空,AJAX_asp.net中mvc使用ajax提交参数的匹配问题解决探讨,想到在asp.net的mvc中如果使用aja - phpStudy...

    asp.net中mvc使用ajax提交参数的匹配问题解决探讨 想到在asp.net的mvc中如果使用ajax向服务端传递参数时如果参数是一个类或者是个数组(或List集合)以及更复杂的对象时,服务端总 ...

最新文章

  1. 美媒全球大学排名:清华超麻理跃居计算机专业第一
  2. linux 压缩 解压 命令大全
  3. python3报错:importError: dynamic module does not define module export function (PyInit_cv_bridge_boost
  4. acctype mysql assoc_DedeCMS V5.3二次开发经验分享
  5. php中的数组用什么统计,php数组元素统计与值汇总
  6. 学习笔记(十五)——镜像的知识点与注意事项
  7. 新的实现上下文对话的方法
  8. Knockoutjs之observable和applyBindings的使用
  9. Thread.sleep(0)的意义
  10. 如何找到好书?有什么技巧或建议?
  11. MarkDown学习手册
  12. DirectX12(D3D12)基础教程(十)——DXR(DirectX Raytracing)基础教程(上)
  13. 英特尔DRM内核驱动程序默认启用PSR2省电功能
  14. 让你的 Mac 用上最美的屏保,Aerial 使用教程
  15. java农夫过河_C语言实现农夫过河代码及解析
  16. subscript on non-array or too many dimensions
  17. squid代理服务+ip代理池
  18. 爬虫(python)—下载技巧
  19. R语言 NetCoMi包 Co-occurrence网络图 微生物16S 网络比较 核心物种
  20. error LNK1123: 转换到 COFF 期间失败

热门文章

  1. (转)elasticsearch6.0版本安装head插件
  2. 安装deepin linux
  3. TypeScript 素描 - 模块解析、声明合并
  4. nhibernate3 linq的的select 操作
  5. Spark之伪分布式搭建、伪分布式Hadoop、Hive安装
  6. Hystrix之外健壮微服务的新选择:Sentinel 发布首个生产版本 1
  7. ESXI6.5 最新版尝鲜安装图解
  8. Linux workqueue工作原理 【转】
  9. java解析xml的几种方式
  10. Mybatis源码研究6:元数据(metadata)