系列目录

DataTokens和Areas机制

到目前为止Route对象只剩下DataTokens属性没有涉及,事实上这个Areas机制的核心。

DataTokens实际上也是一个RouteValueDictionary,在用MapRoute方法构造在Route构造的时候,可以传一个namespaces字符串数组,这个参数会构造成Route对象的DataTokens["Namespaces"],它的值将被MVC框架优先用来在对应的名字空间中查找相应的Controller。 如果在指定的名字空间中能找到Controller,那么,就算在其他名字空间中有相同名字的Controller(大小写敏感)也没关系;如果在指定的 名字空间中没有找到Controller,那么将在所有引用的程序集中查找,此时如果出现重复名字的Controller,那么将出现多个匹配的错误。这 种行为是DefaultControllerFactory实现的,关于DefaultControllerFactory将在以后分析。

Areas机制是这样的一种机制:在不同的Area中可以有相同名字的Controller,也就是说Controller的名字可以重复了!这样 整个web应用程序可以按功能划分成几个模块,每个模块是一个Area,每个Area互相独立,可以独立地由某个开发人员随意定义URL或 Controller而不影响其他Area。

比如:有管理员和用户两个模块,也许需要如下的URL:

Admin/Home/Index

User/Home/Index

于是可以用VS集成的Area生成模板创建两个Area:Admin和User,分别地,由两个开发人员分别负责开发,他们都需要用 HomeController和Index方法,有了Areas机制,HomeController被分别放到两个不同的名字空间中,这就不会有冲突。

讲到这里你也许隐约明白DataTokens和Areas机制的某种关系了。在vs创建Areas的时候到底做了哪些事情呢?

一、首先在每个Area中Controller都将被放置到一个名字空间中,例如:MyAppName.Areas.Admin.Controllers;

二、为每个Area创建一个AreaRegistration的继承类,如果是Admin的Area将是AdminAreaRegistration。在这个类中重写AreaName属性和RegisterArea方法:

1
2
3
4
5
6
7
8
public override void RegisterArea(AreaRegistrationContext context)
{
    context.MapRoute(
        "Admin_default",
        "Admin/{controller}/{action}/{id}",
        new { action = "Index", id = UrlParameter.Optional }
    );
}

可以看到在RegisterArea方法中也调用了MapRoute方法注册路由。需要注意的是这个的MapRoute虽然也是操作全局路由表,但是它的实现略有不同:

1.首先设置的URL Pattern是以Area名字开头的,这样做是必要的,毕竟这个URL Pattern最终是放在全局中的;

2.它会将DataTokens["Namespaces"]设置成当前Area的名字空间,比如 MyAppName.Areas.Admin.*。结果是,当一个请求到来是,DefaultControllerFactory会优先到这个名字空间下 查找Controller。而且会增加一个DataTokens["UseNamespaceFallback"],并设置为false,这样当且仅当显示设置的名字空间中有需要的Controller时,才能成功,其他名字空间的的同名Controller将无效;

3.最后,还会添加一个叫DataTokens["area"]的键值,并设置为当前Area名字,这是为了在反向映射(outbounding)URL的时候使用。因此在MVC中"area"键是有特殊用途的,所以不能用于url pattern的参数。

在Areas机制中有一个冲突需要注意。由于路由表只有一张,如果当前的url映射到了"root area"(即在Global域),那么将从当前所有的名字空间中查找Controller,此时很可能找到多个匹配的。解决方案是,在 Globla.asax.cs中设置路由的时候,为DataTokens设置优先名字空间。

进一步扩展

当从深层次了解了路由工作机制后,就进行一些自定义了。

自定义RouteBase

有前面的分析,可以知道,在inbound时Route(继承自RouteBase)需要提供一个RouteData,因此RouteBase定义 了GetRouteData方法,这是我们可以自己实现的;同时,GetVirtualPath方法用于outbound。所以,只要实现了这两个方法就 可以完成一个RouteBase的实现。比如:当想要把一个老的网站改造成新的基于MVC架构的,又不想使原来的url失效,简单的处理方案可以像下面这 样:

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
public class LegacyUrlsRoute : RouteBase
{
    // In practice, you might fetch these from a database
    // and cache them in memory
    private static string[] legacyUrls = new string[] {
    "~/articles/may/zebra-danio-health-tips.html",
    "~/articles/VelociraptorCalendar.pdf",
    "~/guides/tim.smith/BuildYourOwnPC_final.asp"
    };
    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        string url = httpContext.Request.AppRelativeCurrentExecutionFilePath;
        if(legacyUrls.Contains(url, StringComparer.OrdinalIgnoreCase)) {
            RouteData rd = new RouteData(this, new MvcRouteHandler());
            rd.Values.Add("controller", "LegacyContent");
            rd.Values.Add("action", "HandleLegacyUrl");
            rd.Values.Add("url", url);
            return rd;
        }
        else
        return null; // Not a legacy URL
    }
    public override VirtualPathData GetVirtualPath(RequestContext requestContext,
        RouteValueDictionary values)
    {
        // This route entry never generates outbound URLs
        return null;
    }
}

自定义IRouteHandler

通常在MVC框架中IRouteHandler由MvcRouteHandler实现,这个MVC框架的入口。尽管如此,我们还是可以自己定义一个 IRouteHandler。当我们需要对某些请求做优化处理的时候可以考虑这样做。因为,自定义实现IRouteHandler意味着将忽略MVC框 架。比如下面这个实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class HelloWorldHandler : IRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return new HelloWorldHttpHandler();
    }
    private class HelloWorldHttpHandler : IHttpHandler
    {
        public bool IsReusable { get { return false; } }
        public void ProcessRequest(HttpContext context)
        {
            context.Response.Write("Hello, world!");
        }
    }
}

劳动果实,转载请注明出处:http://www.cnblogs.com/P_Chou/archive/2010/11/15/details-asp-net-mvc-04.html

深入理解ASP.NET MVC(4)的更多相关文章

  1. 七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC

    系列文章 七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC 七天学会ASP.NET MVC (二)——ASP.NET MVC 数据传递 七天学会ASP.NET MVC (三)— ...

  2. [转载]深入理解ASP.NET MVC之ActionResult

    Action全局观 在上一篇最后,我们进行到了Action调用的“门口”: 1 if (!ActionInvoker.InvokeAction(ControllerContext, actionNam ...

  3. 深入理解ASP.NET MVC Day1

    深入理解ASP.NET MVC   ASP.NET vs MVC vs WebForms 许多ASP.NET开发人员开始接触MVC认为MVC与ASP.NET完全没有关系,是一个全新的Web开发,事实上 ...

  4. 七天学会ASP.NET MVC ——深入理解ASP.NET MVC

    七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC   系列文章 七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC 七天学会ASP.NET MVC (二) ...

  5. 深入理解ASP.NET MVC(6)

    系列目录 Action全局观 在上一篇最后,我们进行到了Action调用的“门口”: 1 if (!ActionInvoker.InvokeAction(ControllerContext, acti ...

  6. 深入理解ASP.NET MVC(5)

    系列目录 回顾 系列的前4节深入剖析了ASP.NET URL路由机制,以及MVC在此基础上是如何实现Areas机制的,同时涉及到inbound和outbound很多细节部分.第2节中提到MvcRout ...

  7. 深入理解ASP.NET MVC(目录)

    学ASP.NET MVC2有一段时间了,也针对性的做了个练习.感觉这个框架还是不错的,所以决定要深入系统的学习一下.看到这样一本书: 作者博客:http://blog.stevensanderson. ...

  8. 七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC 【转】

    http://www.cnblogs.com/powertoolsteam/p/MVC_one.html 系列文章 七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC 七天学会A ...

  9. [转载] ASP.NET MVC (一)——深入理解ASP.NET MVC

    个人认为写得比较透彻得Asp.net mvc 文章,所以转载过来,原文链接在最后: ASP.NET vs MVC vs WebForms 许多ASP.NET开发人员开始接触MVC认为MVC与ASP.N ...

  10. 理解ASP.NET MVC的路由系统

    引言 路由,正如其名,是决定消息经由何处被传递到何处的过程.也正如网络设备路由器Router一样,ASP.NET MVC框架处理请求URL的方式,同样依赖于一张预定义的路由表.以该路由表为转发依据,请 ...

随机推荐

  1. 84. Largest Rectangle in Histogram *HARD* -- 柱状图求最大面积 85. Maximal Rectangle *HARD* -- 求01矩阵中的最大矩形

    1. Given n non-negative integers representing the histogram's bar height where the width of each bar ...

  2. Deep Belief Network简介——本质上是在做逐层无监督学习,每次学习一层网络结构再逐步加深网络

    from:http://www.cnblogs.com/kemaswill/p/3266026.html 1. 多层神经网络存在的问题 常用的神经网络模型, 一般只包含输入层, 输出层和一个隐藏层: ...

  3. swiper中的默认值的属性和作用(小程序交流群:604788754)

    swiper中的重要属性: vertical:属性,控制swiper效果是水平切换滚动,还是垂直切换滚动.如果不设置此属性,默认是水平滚动,如果设置:vertical="true" ...

  4. learning uboot bootargs panic parameter

    By passing the kernel panic parameter, the system automatically resets after 3 seconds when kernel p ...

  5. C++ error C2440: “类型转换” : 无法从“std::vector::iterator”转换为“

    原文地址:http://blog.csdn.net/onlyou930/article/details/5602654 圆环套圆环之迭代器 话说这一日是风平浪静,万里乌云,俺的心情好的没得说,收到命令 ...

  6. 1.5 C++ new和delete操作符

    参考:http://www.weixueyuan.net/view/6331.html 在C语言中,动态分配和释放内存的函数是malloc.calloc和free,而在C++语言中,new.new[] ...

  7. L1-024 后天

    如果今天是星期三,后天就是星期五:如果今天是星期六,后天就是星期一.我们用数字1到7对应星期一到星期日.给定某一天,请你输出那天的“后天”是星期几. 输入格式: 输入第一行给出一个正整数D(1 ≤ D ...

  8. 《C语言中分配了动态内存后一定要释放吗?》

    问:比如main函数里有一句 malloc(),后面没有free()1.那么当main结束后,动态分配的内存不会随之释放吗?2.如果程序结束能自动释放,那么还加上free(),是出于什么考虑? 答: ...

  9. php 函数2

  10. [Scala]Scala学习笔记七 正则表达式

    1. Regex对象 我们可以使用scala.util.matching.Regex类使用正则表达式.要构造一个Regex对象,使用String类的r方法即可: val numPattern = &q ...