在ASP.Net MVC 中,如何在Global.asax中配置一個指向Area內部的默認Route

ASP.Net MVC 中配置Route的時候能夠設置一個默認的Route。框架

好比我要在輸入http://localhost的時候默認進入http://localhost/home/index。能夠在Global.asax中這麼配置:ide

C#代碼   收藏代碼
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

C#代碼   收藏代碼
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的源碼中是怎麼作的:

C#代碼   收藏代碼
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的約束。那咱們也來加上看看。

C#代碼   收藏代碼
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時的下面幾句:

C#代碼   收藏代碼
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中的源碼,關鍵的一句就是:

C#代碼   收藏代碼
route.DataTokens["area"] = AreaName; 

就是在註冊Area的Route的時候,會把這個AreaName放進去。

明白了這一點,咱們就能夠來繼續改造咱們註冊route的地方:

C#代碼   收藏代碼
         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機制。

相關文章
相關標籤/搜索