• (转)ASP.NET Mvc 2.0


    转自:http://www.cnblogs.com/terrysun/archive/2010/04/13/1711218.html

    ASP.NET Mvc 2.0 - 1. Areas的创建与执行

    Areas是ASP.NET Mvc 2.0版本中引入的众多新特性之一,它可以帮你把一个较大型的Web项目分成若干组成部分,即Area。实现Area的功能可以有两个组织形式:

    1. 在1个ASP.NET Mvc 2.0 Project中创建Areas。
    2. 创建多个ASP.NET Mvc 2.0 Project,每个Project就是一个Area。

    第2种结构比较复杂,但第1种结构同样可以做到每个Area之间的并行开发,互不影响,所以不推荐第2种方法。

    以ASP.NET Mvc 2.0的默认模板为例:

    1. 首先要新建一个ASP.NET Mvc 2.0的Project,在Project上点击鼠标右键选择Add->Area,在打开的窗口中输入Area的名子(例如:Profile),点击Add按钮,然后将看到下面的结构。P

    名子叫做Profile的Area的结构与根目录下的Controllers,Models和Views的结构是一样的,唯一区别是Profile下面多了一个ProfileAreaRegistration.cs文件。它继承自AreaRegistration类,ProfileAreaRegistration 必须实现AreaRegistration类中的AreaName属性和RegisterArea(AreaRegistrationContext context)方法

    using System.Web.Mvc;
    
    namespace ASP.NET_Mvc_2_Test.Areas.Profile
    {
        public class ProfileAreaRegistration : AreaRegistration
        {
            public override string AreaName
            {
                get
                {
                    return "Profile";
                }
            }
    
            public override void RegisterArea(AreaRegistrationContext context)
            {
                context.MapRoute(
                    "Profile_default",
                    "Profile/{controller}/{action}/{id}",
                    new { action = "Index", id = UrlParameter.Optional }
                );
            }
        }
    }

    AreaName属性用来定义Area的名子, RegisterArea(AreaRegistrationContext context) 方法中可以看出在浏览器的地址栏中URL的样式为Profile/{controller}/{action}/{id},是4级构结,只要将context.MapRoute(…)改为

    public override void RegisterArea(AreaRegistrationContext context)
            {
                context.MapRoute(
                    "Profile_default",
                    "Profile/{action}/{id}",
                    new { controller = "要访问的controller名子", action = "Index", id = UrlParameter.Optional }
                );
            }

    URL的样式会再变为三级结构 Profile/{action}/{id}。

    2. 修改根目录下Views/shared/Site.Master文件,并添加一个名为o”Your Profile”的菜单项并指定area的名子, 示例中Area的名子为Profile。  

    <ul id="menu">              
                        <li><%= Html.ActionLink("Home", "Index", "Home", new { area = ""}, null)%></li>
                        <li><%= Html.ActionLink("Your Profile", "ViewProfile", "Profile", new { area = "Profile" }, null)%></li>
                        <li><%= Html.ActionLink("About", "About", "Home", new { area = ""}, null)%></li>
    </ul>

    注意:Home和About不属于任何Area,但是也要通过匿名对象的方式声明area,如果没有声明Area,当进入到Profile的某个view时, Home和About的会的URL会变为Profile/Home, Profile/About,点击Home或About时会有异常抛出,所以当页面上的某个链接不属于任何一个Area并且有可能被多个Area可享的话,一定要加上new { area = ""}

    3. 只有匹配正确的Route才能显示Area中的View,Area中的Route已经配置好,但它是如何被加入到RouteTable中的?

      3.1 首先在Global.asax.cs的Application_Start()方法中调用了AreaRegistration.RegisterAllAreas()方法,这个方法的目地主是找出所有继承了AreaRegistration的类,并执行RegisterArea(…)方法来完成注册

    public static void RegisterAllAreas() {
                RegisterAllAreas(null);
            }
    
            public static void RegisterAllAreas(object state) {
                RegisterAllAreas(RouteTable.Routes, new BuildManagerWrapper(), state);
            }
    
            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);
                }
            }

        3.1.1 TypeCacheUtil.GetFilteredTypesFromAssemblies(…)方法用来找出所有继承了AreaRegistration类的Type对象:

    public static List<Type> GetFilteredTypesFromAssemblies(string cacheName, Predicate<Type> predicate, IBuildManager buildManager) {
                TypeCacheSerializer serializer = new TypeCacheSerializer();
    
                // first, try reading from the cache on disk
                List<Type> matchingTypes = ReadTypesFromCache(cacheName, predicate, buildManager, serializer);
                if (matchingTypes != null) {
                    return matchingTypes;
                }
    
                // if reading from the cache failed, enumerate over every assembly looking for a matching type
                matchingTypes = FilterTypesInAssemblies(buildManager, predicate).ToList();
    
                // finally, save the cache back to disk
                SaveTypesToCache(cacheName, matchingTypes, buildManager, serializer);
    
                return matchingTypes;
            }

         在GetFilteredTypesFromAssemblies(…)方法中,先从缓存中读取匹配的类型(缓存用于.Net Framework 4.0中,示例程序用VS2008在.NET 3.5环境下,暂不讨论缓存的应用)。缓存没有数据返回,调用FilterTypesInAssemblies(…)方法返回List<Type>对象, 这时返回的List<Type>才是继承了AreaRegistration类的Type对象, 下面的代码是FilterTypesInAssemblies方法的源码:

    private static IEnumerable<Type> FilterTypesInAssemblies(IBuildManager buildManager, Predicate<Type> predicate) {
                // Go through all assemblies referenced by the application and search for types matching a predicate
                IEnumerable<Type> typesSoFar = Type.EmptyTypes;
    
                ICollection assemblies = buildManager.GetReferencedAssemblies();
                foreach (Assembly assembly in assemblies) {
                    Type[] typesInAsm;
                    try {
                        typesInAsm = assembly.GetTypes();
                    }
                    catch (ReflectionTypeLoadException ex) {
                        typesInAsm = ex.Types;
                    }
                    typesSoFar = typesSoFar.Concat(typesInAsm);
                }
                return typesSoFar.Where(type => TypeIsPublicClass(type) && predicate(type));
            }

        与寻找controll的方法相似,找出所有assembly中的所有Type并通过TypeIsPublicClass和predicate的过滤出继承了AreaRegistration类的Type对象

        3.1.2 在GetFilteredTypesFromAssemblies(…)方法中如果.Net Framework的版本不是4.0, 最后的SaveTypesToCache(…)方法也不会执行

                  以后会对.Net Framework 4.0下的ReadTypesFromCache(…)和SaveTypesToCache(…)进行补充

      3.2 遍历返回的List<Type>对象,反射出AreaRegistration 对象并调用它的CreateContextAndRegister(…)方法

    internal void CreateContextAndRegister(RouteCollection routes, object state) {
                AreaRegistrationContext context = new AreaRegistrationContext(AreaName, routes, state);
    
                string thisNamespace = GetType().Namespace;
                if (thisNamespace != null) {
                    context.Namespaces.Add(thisNamespace + ".*");
                }
    
                RegisterArea(context);
            }

    在CreateContextAndRegister(…)方法中创建一个AreaRegistrationContext 对象并做为RegisterArea(…)方法的参数,RegisterArea刚好是AreaRegistration 的继承类中重写方法,在RegisterArea方法只要调用AreaRegistrationContext 类的MapRoute(…)方法就可能完成一个新的Route的注册。

    示例代码 下载

     
    发表评论
     
      
    #1楼 2010-04-13 17:49 | Dozer  
    我也看过这部分的源码,有个问题想解决,不知道能不能不修改源码。

    就是,比如我有2个Area,那这两个Area的注册顺序能不能固定?

    从原来看来,它不是固定的,因为是利用反射得到了一个集合

    不知道博主有何解决办法?
      
    #2楼 2010-04-13 18:01 | 黑子范  
      
    #3楼[楼主] 2010-04-13 22:26 | Terry Sun  
    @Dozer
    首先第一点,绝对不可以修改源码 :)

    固定是可以的,首先不需要创建继承于AreaRegistration的类,将每个area的route注册写到Global.asax.cs中, 如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
     
        // Register Area
    routes.MapRoute(
                    "Profile_default",
                    "Profile/{action}/{id}",
                    new { controller = "Profile", action = "index", id = UrlParameter.Optional }
                    );
     
        routes.MapRoute(
                    "Default", // Route name
                    "{controller}/{action}/{id}",
                    new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
                );
     
    }
      
    #4楼[楼主] 2010-04-13 22:27 | Terry Sun  
    @黑子范
    :)
      
    #5楼 2010-04-13 23:10 | Dozer  
    @Terry Sun
    这个我还真没试过。。。

    可以直接移出来吗?我去试一下
      
    #6楼 2010-04-13 23:40 | Dozer  
    @Terry Sun
    测试过了,有问题,移出来以后,route是正常了,但是这时候搜寻view讲不会在 Areas/myareas/View下搜索

    出错
      
    #7楼[楼主] 2010-04-14 09:07 | Terry Sun  
    @Dozer
    Sorry,是我没有说明白,一定要声明AreaName并保存到Route.DatattTokens中,否则不能定位到相应的area目录,下面的代码是两个area,先注册Profile再注册Blog

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
     
                #region Register Areas
                // Profile ares.
                Route areaProfile = routes.MapRoute(
                     "Profile_default",
                     "Profile/{action}/{id}",
                     new { controller = "Profile", action = "View", id = UrlParameter.Optional}
                 );
                areaProfile.DataTokens["area"] = "Profile";
                areaProfile.DataTokens["UseNamespaceFallback"] = true;
     
                // Blog ares.
                Route areaBlog = routes.MapRoute(
                     "Blog_default",
                     "Blog/{action}/{id}",
                     new { controller = "Blog", action = "View", id = UrlParameter.Optional}
                 );
                areaBlog.DataTokens["area"] = "Blog";
                areaBlog.DataTokens["UseNamespaceFallback"] = true;
     
                #endregion
     
                routes.MapRoute(
                    "Default", // Route name
                    "{controller}/{action}/{id}", // URL with parameters
                    new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
                );
     
            }

     

  • 相关阅读:
    JavaScript知识点总结
    Python错误:ImportError: No module named 'requests'
    The type java.lang.CharSequence cannot be resolved. It is indirectly referenced from required .class
    Html重点知识
    使用Gson中的JsonElement所遇到的坑
    AndroidStudio:The number of method references in a .dex file cannot exceed 64K错误
    使用TextUtils.isEmpty()遇到的坑
    Gson常用方法
    AndroidStudio——java.lang.UnsatisfiedLinkError错误
    RecyclerView点击,移动到中间位置
  • 原文地址:https://www.cnblogs.com/jiajinyi/p/4060055.html
Copyright © 2020-2023  润新知