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

转自: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的注册顺序能不能固定?

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

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

支持(0)反对(0)

#2楼 2010-04-13 18:01 | 黑子范

mark

支持(0)反对(0)

#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

            );

}

支持(0)反对(0)

#4楼[楼主] 2010-04-13 22:27 | Terry Sun

@黑子范
:)

支持(0)反对(0)

#5楼 2010-04-13 23:10 | Dozer

@Terry Sun
这个我还真没试过。。。

可以直接移出来吗?我去试一下

支持(0)反对(0)

#6楼 2010-04-13 23:40 | Dozer

@Terry Sun
测试过了,有问题,移出来以后,route是正常了,但是这时候搜寻view讲不会在 Areas/myareas/View下搜索

出错

支持(0)反对(0)

#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

            );

        }

 

时间: 2024-10-08 04:27:16

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

asp.net mvc 3.0 知识点整理 ----- (4).HtmlHelper(Html 辅助方法)介绍

在View视图中,Html的类型是System.Web.Mvc.HtmlHelper<T>, 所有的辅助方法都需要和ModelState交互.那么,ModelState是什么呢?它是模型绑定的附属品,并且存有模型绑定期间检测到的所有验证错误.以及用户提交用到来更新模型的原始值.本篇博文,我们主要来介绍下一些常用的html辅助方法的主要作用和使用方法. 1. Html.BeginForm()和Ajax.BeginForm().   Html.BeginForm(): 同于传统的表单提交,主要是生

Asp.net mvc 4.0 高级编程 百度云下载

Asp.net mvc 4.0 高级编程 百度云下载地址:链接:http://pan.baidu.com/s/1o6zFvOe 密码:xyss 1.基于 ASP.NET MVC4.0 + WebAPI + EasyUI + Knockout 的架构设计开发 2.采用MVC的框架模式,具有耦合性低.重用性高.生命周期成本低.可维护性高.有利软件工程化管理等优点 3.采用WebAPI,客户端完全摆脱了代理和管道来直接进行交互 4.采用EasyUI前台UI界面插件,可轻松的打造出功能丰富并且美观的UI

asp.net mvc 3.0 知识点整理 ----- (2).Controller中几种Action返回类型对比

通过学习,我们可以发现,在Controller中提供了很多不同的Action返回类型.那么具体他们是有什么作用呢?它们的用法和区别是什么呢?通过资料书上的介绍和网上资料的查询,这里就来给大家列举和大致的概括下. (1). ActionResult(base):最基本的Action类型,返回其他类型都可以写ActionResult. (2). ContentResult:返回ContentResult用户定义的内容类型. public ActionResult Content() { return

我要学ASP.NET MVC 3.0(十三): MVC 3.0 防止跨站点请求伪造 (CSRF) 攻击

我要学ASP.NET MVC 3.0(十三): MVC 3.0 防止跨站点请求伪造 (CSRF) 攻击 概述      众所周知,ASP.Net MVC程序在浏览器运行时产生了标准的Html标签,包括浏览器要发送的关键数据等内容都在Html内容里面,听起来不错,但是假如我们仿造类似的Html内容,更改里面关键数据,在浏览器运行起来会怎么样呢?好下面我们就做这样一个例子.       CSRF攻击例子 首先我们拿以前做好的person/edit作为例子 先看控制器代码 //初始页面        

ASP.NET MVC 4.0 升级到 5.0遇到的问题及解决思路

先说一下项目的情况 这个项目是公司的一个官网,之前同事写的,用的.NET 和ASP.NET MVC 4.0的.我用的新开发环境是VS2015,在原来的项目基础之上不能创建新的Controller.我就自定义一个Controller类,集成Controller,也可以创建View.调试运行都可以.后来想尝试局域网环境发布,用的是VS自带的发布功能.供公司其他同事浏览,发现一个问题:新建的Controller相关页面和在原有Controller里创建的页面都没有生成,就是没有发布成功.一开始还没注意

asp.net mvc 3.0 知识点整理 ----- (3).asp.net mvc 3 和asp.net mvc 4 对比

asp.net mvc的版本更新很快,每个版本都在前一个版本的基础上,进行性能的优化和功能的完善和提升. 以下,便是我对比了下两个版本,发现最基本的差异.(更新补充中..) 一.关于配置类Global.asax的不同 为了较少配置类的杂乱代码,asp.net mvc 4 中 将Global.asax文件中的内容单独到 App_Start 下的几个配置文件中去. 在asp.net mvc 3 中: public static void RegisterGlobalFilters(GlobalFil

asp.net MVC 4.0 View回顾——布局页与分部页

asp.net MVC 4.0中总结 视图里加载部分视图几种方法 @RenderPage() 但它不能使用 原来视图的 Model 和 ViewData ,只能通过参数来传递. 1 @RenderPage("~/Shared/Component/Dialog.cshtml", new { title = "Hello world!", content="Nani" }) 分部视图接收数据通过Page 1 <div id="dial

ASP.NET MVC 4.0的Action Filter

有时候你想在调用action方法之前或者action方法之后处理一些逻辑,为了支持这个,ASP.NET MVC允许你自定义创建action过滤器.Action过滤器是自定义的Attributes,用来标记添加Action方法之前或者Action方法之后的行为到控制器类中的Action方法中. 什么情况下可能会用到action过滤的地方: 日志,异常处理 身份验证和授权 - 限制用户的访问 输出缓存 - 保存一个Action的结果 网络爬虫的过滤 本地化 动态Action - 将一个Action注

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

原文:安装了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: (0x80070643), "安装时发生严重错误 &qu