转自: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按钮,然后将看到下面的结构。

名子叫做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
            );
 
        }

 

(转)ASP.NET Mvc 2.0 - 1. Areas的创建与执行的更多相关文章

  1. 2.第一个ASP.NET MVC 5.0应用程序

    大家好,上一篇对ASP.NET MVC 有了一个基本的认识之后,这一篇,我们来看下怎么从头到尾创建一个ASP.NET MVC 应用程序吧.[PS:返回上一篇文章:1.开始学习ASP.NET MVC] ...

  2. 返璞归真 asp.net mvc (6) - asp.net mvc 2.0 新特性

    原文:返璞归真 asp.net mvc (6) - asp.net mvc 2.0 新特性 [索引页][源码下载] 返璞归真 asp.net mvc (6) - asp.net mvc 2.0 新特性 ...

  3. ASP.NET MVC 4.0中选择Windows 验证默认出错拒绝访问的原因和解决方案

    在VS 2012或者2013 中,根据模板创建一个ASP.NET MVC 4.0的应用程序,选择下面的模板 然后选择Intranet Application 不对源代码做任何修改,直接按下F5调试,会 ...

  4. 安装了VS2010 sp1 后再安装ASP.NET MVC 3.0的问题

    安装了VS2010 sp1 后再安装ASP.NET MVC 3.0的问题(Final Result: Installation failed with error code: (0x80070643) ...

  5. 返璞归真 asp.net mvc (13) - asp.net mvc 5.0 新特性

    [索引页][源码下载] 返璞归真 asp.net mvc (13) - asp.net mvc 5.0 新特性 作者:webabcd 介绍asp.net mvc 之 asp.net mvc 5.0 新 ...

  6. ASP.NET MVC 3.0 Controller基础

    ASP.NET MVC 3.0 Controller基础   1.Controller类与方法 Controller(控制器)是ASP.NET MVC的核心,负责处理浏览器请求,并作出响应.Cotro ...

  7. 从零开始学习ASP.NET MVC 1.0

    转自:http://www.cnblogs.com/zhangziqiu/archive/2009/02/27/ASPNET-MVC-1.html <从零开始学习ASP.NET MVC 1.0& ...

  8. ASP.NET MVC 4.0的Action Filter

    有时候你想在调用action方法之前或者action方法之后处理一些逻辑,为了支持这个,ASP.NET MVC允许你自定义创建action过滤器.Action过滤器是自定义的Attributes,用来 ...

  9. 安装了VS2010 sp1 后再安装ASP.NET MVC 3.0的问题(Final Result: Installation failed with error code: (0x80070643), "安装时发生严重错误 " (Ela)

    原文:安装了VS2010 sp1 后再安装ASP.NET MVC 3.0的问题(Final Result: Installation failed with error code: (0x800706 ...

随机推荐

  1. VC中GBK与UTF8转化

    void ConvertGBKToUtf8(CString& strGBK) {    int len=MultiByteToWideChar(CP_ACP, 0, (LPCTSTR)strG ...

  2. 八、MPxToolCommand, tool command

    1. Tool Property Sheets: 是用来更改context属性的编辑框,类似于attribute editor.(property和attribute本质上是一个意思)作用于activ ...

  3. COSBench性能测试配置--一张图说明一切

    COSBench性能测试配置--一张图说明一切: 测试配置,并发数,运行时间设置  

  4. PreparedStatement解决sql注入问题

    总结 PreparedStatement解决sql注入问题 :sql中使用?做占位符 2.得到PreparedStatement对象 PreparedStatement pst=conn.prepar ...

  5. ios base64图片上传失败问题

    今天做图片上传,后台用的是base64解密图片二进制文件,以前都是用表单上传来解决图片上传的,现在后台没有人改,所以研究下base64上传. 需要将图片base64加密,但是调用 [data base ...

  6. Address already in use的解决方法

    当客户端保持着与服务器端的连接,这时服务器端断开,再开启服务器时会出现: Address already in usr. 可以用netstat -anp | more 可以看到客户端还保持着与服务器的 ...

  7. Java第一天学习笔记整理

    一.关键字 java的关键字对java的编译器有特殊的意义,他们用来表示一种数据类型,或者表示程序的结构等,关键字不能用作变量名.方法名.类名.包名. 常见的关键字: 用于定义数据类型的关键字 cla ...

  8. COleChangeSourceDialog不能Change Source的解决方法

      在微软给的例子OClient中,有选中一个OLE对象然后Change Source的功能,但是会报错.分析了一下是这样的: void CMainView::OnOleChangeSource() ...

  9. RHEL 7.0 本地配置yum源

    RHEL 7.0 本地配置yum源  yum简介  yum = Yellow dog Updater, Modified 主要功能是更方便的添加/删除/更新RPM包. 它能自动解决包的倚赖性问题. 它 ...

  10. CommandArgument传多个参数

    CommandArgument='<%#Eval("id")+","+Eval("interName") %>'