前一段時間接觸了MVC的Area能夠將模型、控制器和視圖分紅各個獨立的節點。分區以後,區域路由註冊的需求就出來了。html
默認的編程
在MVC項目上右鍵添加區域以後,在文件夾下會自動添加一個FolderNameAreaRegistration.cs的文件。mvc
public class AdminAreaRegistration : AreaRegistration { public override string AreaName { get { return "Admin"; } } public override void RegisterArea(AreaRegistrationContext context) { context.MapRoute( "Admin_default", "Admin/{controller}/{action}/{id}", new { action = "Index", id = UrlParameter.Optional } ); } }
在其中,定義了一個繼承AreaRegistration的類,類下面 重寫了AreaName和RegisterArea。固然,這一串代碼已經能夠很好的解決區域的路由註冊問題了。asp.net
可是對於這重複的代碼有點排斥,另外一個也想看看有沒有其餘的替換方式。ide
想看看能不能在路由註冊那裏統一管理函數
插曲一工具
以前在開始接觸分區的時候,碰到過區域下頁面的layout連接錯誤的問題,後來的解決方式是在ActionLink的routeValue參數裏面定義area=""。this
狀況和這裏的有點像,不一樣的是,上面的須要清除area,這裏須要添加area。url
插曲二spa
最近在看《asp.net mvc4高級編程》這本書,接觸到一個頗有用的工具RouteDebugger。
過程一
路由註冊那裏,調用的是routes.MapRoute函數,來向RouteTable.Routes中添加route。這個函數有好幾個擴展,結合上面插曲一的思路,在擴展函數的defaults裏面,嘗試添加屬性area="Test":
routes.MapRoute( name: "Test_Default", url: "Test/{controller}/{action}/{id}", defaults: new { area = "Test", controller = "AAA", action = "Index", id = UrlParameter.Optional }, namespaces: new string[] { "MVCTest.Areas.Test.Controllers" });
調試經過RouteDebugger看:
輸入/Test/AAA/Index,頁面報錯,此路不通。
過程二
同事研究這塊時,發現除了默認AreaRegistration類之外的方法:
[RouteArea("Admin")] [RoutePrefix("Test")] [Route("{action=index}")] public partial class TestController : Controller { }
在區域下的Controller上面添加Route相關特性。主要就三個:Route、RouteArea和RoutePrefix。第一個定義Area,第二個定義Controller,第三個定義默認action值爲index。實際調試後,發現前臺準確的匹配到了路由,思路OK
到此,結合RouteDebugger,再調試到前臺,咱們能夠看到:
從這個圖能夠看出,MapRoute的數據定義了Url、Defaults和Constraints,後面的DataTokens不能經過MapRoute函數裏面傳入。
查看源代碼:
public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) { if (routes == null) { throw new ArgumentNullException("routes"); } if (url == null) { throw new ArgumentNullException("url"); } Route route = new Route(url, new MvcRouteHandler()) { Defaults = CreateRouteValueDictionaryUncached(defaults), Constraints = CreateRouteValueDictionaryUncached(constraints), DataTokens = new RouteValueDictionary() }; ConstraintValidation.Validate(route); if ((namespaces != null) && (namespaces.Length > 0)) { route.DataTokens[RouteDataTokenKeys.Namespaces] = namespaces; } routes.Add(name, route); return route; }
注意,上面的DataTokens是new了一個RouteValueDictionary對象。
而想要注入的area數據正是在DataTokens裏面。因此上面的第一次嘗試失敗,是由於數據注入到了Defaults裏面。
到了這裏,怎麼在RegisterRoutes裏面統一管理區域的路由註冊,思路已經呼之欲出了。
解決方案:
routes.Add(new Route("PaperMaster/{controller}/{action}/{id}" , new RouteValueDictionary(new { controller = "Papers", action = "Index", id = UrlParameter.Optional }) , new RouteValueDictionary() , new RouteValueDictionary(new { area = "PaperMaster", namespaces = "Packmage.Web.Areas.PaperMaster.Controllers" }) , new MvcRouteHandler()));
直接實例化Route對象,輸入它的各個須要的屬性;不用MapRoute,改用Add,直接向RouteTable.Routes中添加route對象。