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

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的注册。

示例代码 下载

分类: ASP.NET Mvc
标签: ASP.NET Mvc
3
0
(请您对文章做出评价)
« 上一篇: 深入分析 ASP.NET Mvc 1.0 – 4. 使用ModelBinder绑定Action的参数
» 下一篇: [转载]ASP.NET 2.0 中的异步页
posted @ 2010-04-13 16:48 Terry Sun 阅读(2323) 评论(10) 编辑 收藏

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

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

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

不知道博主有何解决办法?

  回复   引用   查看    
#2楼 2010-04-13 18:01 | 黑子范        
mark
  回复   引用   查看    
#3楼 [ 楼主 ]2010-04-13 22:26 | Terry Sun        
@ Dozer
首先第一点,绝对不可以修改源码 :)

固定是可以的,首先不需要创建继承于AreaRegistration的类,将每个area的route注册写到Global.asax.cs中, 如下
01 public static void RegisterRoutes(RouteCollection routes)
02 {
03      routes.IgnoreRoute( "{resource}.axd/{*pathInfo}" );
04  
05      // Register Area
06 routes.MapRoute(
07                  "Profile_default" ,
08                  "Profile/{action}/{id}" ,
09                  new { controller = "Profile" , action = "index" , id = UrlParameter.Optional }
10                  );
11  
12      routes.MapRoute(
13                  "Default" , // Route name
14                  "{controller}/{action}/{id}" ,
15                  new { controller = "Home" , action = "Index" , id = UrlParameter.Optional } // Parameter defaults
16              );
17  
18 }

  回复   引用   查看    
#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

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

  回复   引用   查看    
#8楼 2010-04-14 13:00 | Dozer        
@ Terry Sun
谢~ 试验成功~ 但是我昨天想到了另一个方案,测试中~

  回复   引用   查看    
#9楼 2010-12-30 13:51 | 花猫.NET        
我怎么不行啊,不知道是哪儿出了问题
  回复   引用   查看    
#10楼 2011-01-29 08:14 | sansi        

很不错,学习了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值