Mvc系统学习9——Areas学习

  在Mvc2.0中,新增加了一个特性就是Areas。在没有有使用Areas的情况下,我们的Mvc项目组织是下面这样的。当项目庞大的时候,Controllers,Model,View文件下下面势必会有很多文件。项目将难以管理。

      通过使用Areas使我们可以很好的组织项目,通过单机添加Areas(区域),使用Areas来组织项目。可以得到新的项目组织结构。

      First,Second对应着我们项目的子模块(First,Second命名不是很好)。在这两个文件夹下,有各自独立的Controllers,Models,Views。此外还多了个文件AreaRegistration为后缀的.cs文件. 这个文件主要的作用是给Areas下的子模块配置路由。在全局文件Global.asax中的Application_Start事件里有这么一句代码 AreaRegistration.RegisterAllAreas(),通过mvc源码可以发现通过这句代码最后会调用各个AreaRegistration类,实现路由的注册。

//重写了AreaName用于给DataToken["area"]赋值
     public class FirstAreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get
            {
                return "First";
            }
        }

        //这里会添加一个相应的Area名称的前缀,因为下面这样的添加也是作用到全局路由表的.
        //而且这里的MapRoutes,和在全局的MapRoutes是不同的
        //这时AreaRegistrationContext里面的方法,它里面的方法会自动给DataToken["area"]键赋值当前的AreaName 
         public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "First_default",
                "First/{controller}/{action}/{id}",
                new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
View Code

       当调用 AreaRegistration.RegisterAllAreas()时,会最后调用下面这个方法。通过下面的代码可以得出,这个方法会通过反射得出所有的AreaRegistration的Type实例。接下来依次通过Activator创建实例,进而调用CreateContentAndRegister方法。

internal static void RegisterAllAreas(RouteCollection routes, IBuildManager buildManager, object state) {
            List<Type> areaRegistrationTypes = TypeCacheUtil.GetFilteredTypesFromAssemblies(_typeCacheName, IsAreaRegistrationType, buildManager);
            foreach (Type areaRegistrationType in areaRegistrationTypes) {
                AreaRegistration registration = (AreaRegistration)Activator.CreateInstance(areaRegistrationType);
                registration.CreateContextAndRegister(routes, state);
            }
        }
View Code

       registration.CreateContextAndRegister方法:

internal void CreateContextAndRegister(RouteCollection routes, object state) {
            //实例化一个AreaRegistrationContext 实例,AreaName已经传递给AreaRegistrationContext了
             AreaRegistrationContext context = new AreaRegistrationContext(AreaName, routes, state);

            string thisNamespace = GetType().Namespace;
            if (thisNamespace != null) {
                context.Namespaces.Add(thisNamespace + ".*");
            }
            //调用注册方法,这个方法在各个AreaRegistration中被重写
             RegisterArea(context);
        }
View Code

      各个AreaRegistration重写的RegisterArea(context)方法里面通过调用AreaRegistrationContext的Maproute方法来实现注册,这个方法最后的调用方法是下面这个。可以发现下面这个方法也会调用RouteCollection的MapRoute方法,调用这个方法之后,又向route的DataTokens字典的area和UseNamespaceFallback键设置值。这有什么作用?

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;
        }
View Code

        还有几个疑问待解决:

        1.Area下的路由过程是怎么样的?
        2.在Area下可以实现不同的Area有相同的ControllerName,可以在全局的Global.ascx进行文件配置,但是如果是同名的Controller则会出现错误,而对没有同名的Controller进行配置则不会,这是为什么?

        比如在First,Second都有HomeController,如果在全局的Global.ascx文件进行配置,下面的配置不会出错,但是如果namespaces是MvcAreaDemo2.Areas.First时则会出现错误。这时为什么?如果没有用同名的Controller则namespace是MvcAreaDemo2.Areas.First和MvcAreaDemo2.Areas.First.Controllers都没有错。

routes.Add(new Route("Index1", new MvcRouteHandler())
            {
                Defaults = new RouteValueDictionary(new { controller = "Home", action = "Index", id = UrlParameter.Optional }),
                DataTokens = new RouteValueDictionary(new { area = "First", namespaces = new[] { "MvcAreaDemo2.Areas.First.Controllers" } })
                
            });

            routes.Add(new Route("Index2", new MvcRouteHandler())
            {
                Defaults = new RouteValueDictionary(new { controller = "Home", action = "Index", id = UrlParameter.Optional }),
                DataTokens = new RouteValueDictionary(new { area = "Second", namespaces = new[] { "MvcAreaDemo2.Areas.Second.Controllers" } })

            });
View Code

        3.在Area的使用况下,如果要跳转到另外一个Area的页面,则使用Html.ActionLink进行编写似乎更加麻烦了,有木有更加简便的方法?

明确个目标,一直走下去
原文地址:https://www.cnblogs.com/fhlj/p/3615244.html