深入理解ASP.NET MVC(4)

系列目录

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

时间: 2024-08-07 00:18:53

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

深入理解ASP.NET MVC Day1

深入理解ASP.NET MVC ASP.NET vs MVC vs WebForms 许多ASP.NET开发人员开始接触MVC认为MVC与ASP.NET完全没有关系,是一个全新的Web开发,事实上ASP.NET是创建WEB应用的框架而MVC是能够用更好的方法来组织并管理代码的一种更高级架构体系,所以可以称之为ASP.NET MVC. 我们可将原来的ASP.NET称为 ASP.NET Webforms,新的MVC 称为ASP.NET MVC. ASP.NET Web Form ASP.NET 在过

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

ASP.NET vs MVC vs WebForms 许多ASP.NET开发人员开始接触MVC认为MVC与ASP.NET完全没有关系,是一个全新的Web开发,事实上ASP.NET是创建WEB应用的框架而MVC是能够用更好的方法来组织并管理代码的一种更高级架构体系,所以可以称之为ASP.NET MVC. 我们可将原来的ASP.NET称为 ASP.NET Webforms,新的MVC 称为ASP.NET MVC. ASP.NET Web Form ASP.NET 在过去的十二年里,已经服务并成功实现

深入理解ASP.NET MVC(6)

系列目录 Action全局观 在上一篇最后,我们进行到了Action调用的“门口”: 1 if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) 在深入研究调用过程的细节前,先有一个总体的认识是很有帮助的.InvokeAction方法大致是按照这样的顺序进行的: 查找action:MVC内部查找action的方法似乎有点复杂,涉及到一个ActionDescriptor的东西,但是原理上是通过反射,在以后的文章中会有所涉及.

深入理解ASP.NET MVC(5)

系列目录 回顾 系列的前4节深入剖析了ASP.NET URL路由机制,以及MVC在此基础上是如何实现Areas机制的,同时涉及到inbound和outbound很多细节部分.第2节中提到MvcRouteHandler是MVC框架的入口,这节开始,从MvcRouteHandler往下说开去. Controller的创建过程:Builder和Factory MvcRouteHandler的实现仅仅是通过GetHttpHandler方法返回一个MvcHandler实例,MvcHandler从Route

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

个人认为写得比较透彻得Asp.net mvc 文章,所以转载过来,原文链接在最后: ASP.NET vs MVC vs WebForms 许多ASP.NET开发人员开始接触MVC认为MVC与ASP.NET完全没有关系,是一个全新的Web开发,事实上ASP.NET是创建WEB应用的框架而MVC是能够用更好的方法来组织并管理代码的一种更高级架构体系,所以可以称之为ASP.NET MVC. 我们可将原来的ASP.NET称为 ASP.NET Webforms,新的MVC 称为ASP.NET MVC. A

理解ASP.NET MVC中的ActionResult

通常我们在一个ASP.NET MVC项目中创建一个Controller的时候,Index()方法默认的返回类型都是ActionResult,通过查看UML图,ActionResult实际上是一个抽象类,因此实际返回的类型是该抽象类的子类. Ø ActionResult及其子类的UML图   有关ActionResult及其子类的UML图如下所示: 由于图片比较大,所以在浏览器中看起来可能比较小,也不太方便,大家可以点击这里下载大图,使用专业的图片浏览器打开来看. 下载大图 Ø ActionRes

理解ASP.NET MVC中的ModelBinder

模型绑定的本质 任何控制器方法的执行都受action invoker组件(下文用invoker代替)控制.对于每个Action方法的参数,这个invoker组件都会获取一个Model Binder Object(模型绑定器对象).Model Binder的职责包括为Action方法参数寻找一个可能的值(从HTTP请求上下文).每个参数都可以绑定到不同的Model Binder:但是大部分情况我们都使用的是默认模型绑定器-DefaultModelBinder(如果我们没有显式设置使用自定义的Mod

深入理解ASP.NET MVC(7)

系列目录 Action的定位 再次回到Controller的ExecuteCore方法,回到action调用的入口: 1 if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) 这里的ActionInvoker是个IActionInvoke,它无疑是负责了所有action的调用逻辑,MVC中默认实现这个接口的是ControllerActionInvoke.可以想象ControllerActionInvoke面临的第一个问题是

深入理解ASP.NET MVC(1)

系列目录 ASP.NET MVC请求的服务过程 下图是书中的截图,表述了一次通常的ASP.NET MVC请求的服务过程: 从图中可以初步看出一个HttpRequest是如何被ASP.NET和ASP.NET MVC框架执行的:经过IIS和ASP.NET处理后,Core Routing会首先根据URL匹配物理路径上的文件,如果不能匹配则由核心路由模块执行路由,路由被匹配后,MvcRouteHandler会将这个请求“带入”MVC框架,执行Controller和Action,Action可以直接注入r

[学习笔记] 理解ASP.NET MVC的路由系统

引言 路由,正如其名,是决定消息经由何处被传递到何处的过程.也正如网络设备路由器Router一样,ASP.NET MVC框架处理请求URL的方式,同样依赖于一张预定义的路由表.以该路由表为转发依据,请求URL最终被传递给特定Controller的特定Action进行处理.而在相反的方向上,MVC框架的渲染器同样要利用这张路由表,生成最终的HTML页面并返回URL.所以,理解整个ASP.NET MVC的路由系统,有两个必须出现的关键元素:Controller与Action,有两个方向的操作:传入的