VS2013和VS2015中MVC 区域路由匹配顺序相反
創(chuàng)建測試工程
分別在vs2013和vs2015中創(chuàng)建mvc項目,并創(chuàng)建First、Second、Three三個Area,每個Area下面創(chuàng)建一個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中升序
| 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中降序
| 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中的某個路由注冊有問題,一直沒有顯現(xiàn)出來,升級到VS2015后出現(xiàn)了404就有可能是路由匹配順序?qū)е碌摹栴}參考: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" />
重新訪問頁面查看路由,順序已經(jīng)改變了(對比上面VS2015里的順序),可以通過這種方法把最常用的路由調(diào)到最前面,提高匹配速度。經(jīng)測試添加新的Area后,調(diào)整的路由順序不會變回去,可以放心使用。
參考鏈接:.Net MVC Area Registration Sequence
?
RouteDebugger?簡介
作者地址:ASP.NET Routing Debugger,代碼結構圖如下:
程序集屬性[assembly: PreApplicationStartMethod(typeof(PreApplicationStart), "Start")] 使PreApplicationStart的Start方法在Application_Start方法之前執(zhí)行,
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} </td></tr>", current2, values[current2]);}foreach (string current3 in routeData.DataTokens.Keys){text11 += string.Format("\t<tr><td>{0}</td><td>{1} </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,排在了以前的所有路由之后,出現(xiàn)404錯誤。通過RouteDebugger發(fā)現(xiàn)是路由的順序問題,所以想到上面那個問題應該也是順序問題,不應該是vs2015的缺陷。
?
希望這篇文章可以幫助你避免遇到同樣的問題,覺著有用就推薦一下吧
?
轉(zhuǎn)載于:https://www.cnblogs.com/zeroes/p/vs2015-arearoute-orderbyname-desc.html
總結
以上是生活随笔為你收集整理的VS2013和VS2015中MVC 区域路由匹配顺序相反的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Solidworks如何绘制装饰螺纹线
- 下一篇: Linux基础之-网络配置,主机名设置,