在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机制。

相关文章
相关标签/搜索