ASP.Net MVC 中配置Route的時候能夠設置一個默認的Route。框架
好比我要在輸入http://localhost的時候默認進入http://localhost/home/index。能夠在Global.asax中這麼配置:ide
routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults );
很簡單,對吧。測試
可是若是你想把默認值指向一個Area內部的Controller/Action,要怎麼作呢? this
模仿上面的例子,我是這麼作的:url
新建一個叫作MyArea的area,而後配置路由以下:spa
routes.MapRoute( "Default", // Route name "{area}{controller}/{action}/{id}", // URL with parameters new {area = "MyArea", controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults );
添加了一個area的section,應該能夠了吧。code
運行一下看看:blog
結果是Controller衝突,截圖以下:圖片
這說明了咱們配置的那個{Area}沒起做用。原來MVC的route沒有對Area進行支持。ci
來看看MyAreaAreaRegistration的源碼中是怎麼作的:
public Route MapRoute(string name, string url, object defaults, object constraints, string[] namespaces) { if (namespaces == null && Namespaces != null) { namespaces = Namespaces.ToArray(); } Route route = Routes.MapRoute(name, url, defaults, constraints, namespaces); route.DataTokens["area"] = AreaName; // disabling the namespace lookup fallback mechanism keeps this areas from accidentally picking up // controllers belonging to other areas bool useNamespaceFallback = (namespaces == null || namespaces.Length == 0); route.DataTokens["UseNamespaceFallback"] = useNamespaceFallback; return route; }
它在MapRoute的時候加入了一個namespace的約束。那咱們也來加上看看。
routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new {controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults new[] { "WebArchDemo.Areas.MyArea.*" } );
OK,成功了。不過仔細一看。View不對了。它居然仍是去找Area外面的View,而不是這個Area下面的View.
咱們在ViewEngine的源碼中找一下緣由,關鍵代碼是在尋找View時的下面幾句:
string areaName = AreaHelpers.GetAreaName(controllerContext.RouteData); bool usingAreas = !String.IsNullOrEmpty(areaName); List<ViewLocation> viewLocations = GetViewLocations(locations, (usingAreas) ? areaLocations : null);
ViewEngine會在controllerContext.RouteData中去找AreaName,若是找到的話就用Area中的View,不然用根目錄下的View.那這個AreaName是何時放如RouteData中的呢?
回頭看一下我前面貼出來那段MyAreaAreaRegistration中的源碼,關鍵的一句就是:
就是在註冊Area的Route的時候,會把這個AreaName放進去。
明白了這一點,咱們就能夠來繼續改造咱們註冊route的地方:
var route = routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new {controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults new[] { "WebArchDemo.Areas.MyArea.*" } ); route.DataTokens["area"] = "MyArea";
測試一下,徹底正確。
在實際的項目中,可能直接把默認route指向Area內部的一個Action的概率比較小。不過仍是有一些特殊場景。
咱們經過嘗試來實現這麼一種特殊場景,分析了AreaRegistration的工做原理,也窺探了一下Route和ViewEngine是如何處理Area的。
咱們能夠看到,MVC在儘量少地侵入框架的狀況下,實現了一套Area機制。