Hello World
Spiga

ASP.NET Routing对请求的处理方式

2009-09-29 15:09 by 老赵, 13440 visits

原本这是《关于ASP.NET Routing的几点内容》一文中的一节,不过等写完这节之后发现这块内容已经比较完整了,而且它本身也是独立和最为常见的部分,因此我把它提取出来单独成文。至于那片文章的其他部分我会再修改一下,明天发布。希望这些内容会对您理解ASP.NET Routing工作方式,以及阅读ASP.NET Routing的代码有所帮助。

首先,如果您需要在项目中使用在ASP.NET Routing的功能,则需要在web.config文件中配置一个HttpModule:

<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, ..." />

其次,您应该在Application_Start中向RouteCollection类型的RouteTable.Routes集合中添加一系列RouteBase对象,并为每个RouteBase对象指定一个独立的名称(大小写无关)。当然,您也可以在运行时动态添加或删除内容(RouteCollection对象是线程安全的),只不过我们平时不太会去这么做而已。值得注意的是,RouteCollections里的RouteBase对象,它们的顺序是非常重要的。

UrlRouteModule会监听ASP.NET Request Pipelines的PostResolveRequestCache事件,在这个事件中UrlRouteModule会将当前的HttpContext作为参数调用RouteTable.Routes集合的GetRouteData方法。在RouteCollection的GetRouteData方法中,又会依次将HttpContext传入每一个RouteBase对象的GetRouteData方法,如果中途某个RouteBase对象返回了一个非null的结果,则这个结果便会直接返回给UrlRouteModule。

如果UrlRouteModule调用RouteTable.Routes.GetRouteData方法得到了null,则“一切都像没有发生过”。如果GetRouteData方法得到了结果——一个RouteData对象,此时RouteData.Values便会包含请求中捕获到的数据。RouteData中另一个重要的成员便是RouteData.RouteHandler属性,它返回一个IRouteHandler对象。IRouteHandler接口中只有一个方法GetHttpHandler,它接受RequestContext作为参数,并返回一个IHttpHandler对象。如ASP.NET MVC框架在利用ASP.NET Routing时,便会使用MvcRouteHandler来返回一个MvcHandler对象。

不过,UrlRouteModule在得到了IRouteHandler对象之后,并不会直接调用其GetHttpHandler方法,而是判断它是不是ASP.NET Routing自带的StopRoutingHandler类型。StopRoutingHandler是个特殊的IRouteHandler对象,它的作用只是告诉UrlRouteModule,虽然某个规则匹配成功了,但是——也还是当什么都没发生过吧。因此,如果我们想要“跳过”一些形式的请求,往往则需要将“忽略”功能放在其他所有规则之前。如:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.IgnoreRoute("scripts/{*pathInfo}");
    routes.IgnoreRoute("images/{*pathInfo}");

    routes.MapRoute(
        "Default",                                              // Route name
        "{controller}/{action}/{id}",                           // URL with parameters
        new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
    );
}

IgnoreRoute是定义在ASP.NET MVC中,基于RouteCollection类型的扩展方法。它会向RouteCollection中添加一个Route对象,而这个Route对象在匹配成功时返回的RouteData对象,其RouteHandler属性便为一个StopRoutingHandler,于是余下的Routing规则也不会继续匹配了——这一点和RouteBase对象返回null不同,因为如果返回null,则余下的规则还会依次匹配。如果返回了一个包含StopRoutingHander的RouteData,则剩下的Routing规则全部跳过。

如果UrlRouteModule得到的IRouteHandler对象不是StopRoutingHandler,则便会通过其GetHttpHandler方法获得那个IHttpHandler对象。这个IHttpHandler对象会被放入HttpContext的Items集合中。至此,Request Pipeline的PostResolveRequestCache事件便结束了。

UrlRouteModule还会监听PostMapRequest事件,此时Module便会查找HttpContext.Items集合的特定位置中是否包含一个IHttpHandler对象,如果存在,则会将这个对象设为当前HttpContext对象的Handler属性的值。于是当ASP.NET继续执行下去时,便会调用这个Handler的ProcessRequest方法来处理请求了。

如果这个IHttpHandler对象是MvcHttpHandler,那么它便会从RouteData中获取一些数据,构造Controller对象,执行Action等等。如果它是一个DynamicDataHandler,或是WebForm的HttpHandler,那么剩下的便是各自的模型的处理方式了。

因此,ASP.NET Routing是一个通用的组件,它不涉及到任何具体的请求处理方式。如果您需要,也可以自己基于它进行开发——如FubuMvc项目就是这么做的。

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

31 条回复

  1. xland
    *.*.*.*
    链接

    xland 2009-09-29 15:12:00

    沙发?

  2. 铁打的西西。
    *.*.*.*
    链接

    铁打的西西。 2009-09-29 15:15:00

    哈哈
    好悲哀啊
    工作一年多了
    从深圳回到老家
    找了一个月工作
    居然连一个面试电话也没有
    真的好悲哀
    我几近绝望了

  3. 铁打的西西。
    *.*.*.*
    链接

    铁打的西西。 2009-09-29 15:16:00

    哈哈
    好悲哀啊
    工作一年多了
    从深圳回到老家
    找了一个月工作
    居然连一个面试电话也没有
    真的好悲哀
    我几近绝望了

  4. xland
    *.*.*.*
    链接

    xland 2009-09-29 15:24:00

    老赵最近高产

    老赵你的文章文字一般比代码多
    我觉得我更喜欢代码稍微多一些的

    代码毕竟是程序员的共同语言
    就像五线谱是搞音乐的人的共同语言一样

    Artech的WCF系列
    看一会就要睡觉了
    我觉得还是webabcd写的WCF文章更吸引人

    可能你要说原理讲的不深入
    我觉得应该是先知道怎么做
    然后再去翻MSDN研究它的原理

    总之希望老赵写的代码多一些
    实例的东西多一些

  5. xland
    *.*.*.*
    链接

    xland 2009-09-29 15:28:00

    搞工程和做学问毕竟有区别的

  6. 老赵
    admin
    链接

    老赵 2009-09-29 15:32:00

    @xland
    兄弟,MSDN哪儿有多少原理,它才是代码的源泉。
    如果要知道该怎么做,应该去看MSDN的示例,我是不太写入们文章的啊。
    说起入门文章,我的“趣味编程”挺入门的,所以代码也比较多。

    至于五线谱,我小时候弹过近10年钢琴,看得音乐理论书也不少。
    相信我,我代码占文章的比例,与五线谱占音乐书的比例相比,只多不少。

    搞工程和做学问是有区别,但是再相信我一次:
    如果不以做学问的态度搞工程,那么工程也是搞不好的。
    所以现在“写代码”的那么多,“程序员”却很少。

  7. notlogon[未注册用户]
    *.*.*.*
    链接

    notlogon[未注册用户] 2009-09-29 15:39:00

    看老外的书,都是1.简单介绍 2.来个项目 3.研究原理

    呵呵!

  8. 老赵
    admin
    链接

    老赵 2009-09-29 15:39:00

    @notlogon
    举些例子?哪有那么简单。

  9. Ryan Gene
    *.*.*.*
    链接

    Ryan Gene 2009-09-29 15:47:00

    哟,老赵钢琴几级啊?

  10. xland
    *.*.*.*
    链接

    xland 2009-09-29 15:53:00

    @Jeffrey Zhao
    我是先把东西做出来
    然后在分析学习它的原理的

    如果老赵也这样写文章就好了:
    1:需求说明
    2:代码实现
    3:原理分析
    4:总结扩展
    这样也多好啊(个人观点,呵呵)

    你写的趣味编程你说都是实际项目中遇到的
    但是我看完文章,学到知识了,不知道怎么用,用到哪啊!

    请原谅我的浅薄,呵呵。

  11. 老赵
    admin
    链接

    老赵 2009-09-29 15:56:00

    @Ryan Gene
    六级,不过我当时可以弹十级的曲子,哈哈。

  12. Yankee
    *.*.*.*
    链接

    Yankee 2009-09-29 15:57:00

    老赵,你是俺的偶像。呵呵

  13. 老赵
    admin
    链接

    老赵 2009-09-29 16:00:00

    @xland
    趣味编程不是都写着可以怎么用吗?为什么还不知道用什么地方?

    你先把东西做出来,再分析原理,这是个悖论。
    就好比有人说平时不用学,用到了再学一样。
    你不学,怎么知道用的时候该用什么,怎么用好?

    我建议,你应该设法改变一下学习一个东西的方式,思路。
    你学习起来觉得适应,轻松,但这不一定是有效的方式啊。
    坚持坚持,习惯就好。

  14. notlogon[未注册用户]
    *.*.*.*
    链接

    notlogon[未注册用户] 2009-09-29 16:06:00

    Jeffrey Zhao:
    @xland
    趣味编程不是都写着可以怎么用吗?为什么还不知道用什么地方?

    你先把东西做出来,再分析原理,这是个悖论。
    就好比有人说平时不用学,用到了再学一样。
    你不学,怎么知道用的时候该用什么,怎么用好?

    我建议,你应该设法改变一下学习一个东西的方式,思路。
    你学习起来觉得适应,轻松,但这不一定是有效的方式啊。
    坚持坚持,习惯就好。




    带着做完项目的问题,思考不为是一个好方法啊!,这样更能理解。

    个人愚见。

  15. 老赵
    admin
    链接

    老赵 2009-09-29 16:12:00

    @notlogon
    这点我还是持保留意见啊,问题是平时思考关注出来的,项目是个“触媒”,但关键还在平时思考和个人。
    试想,你平时做项目时,有没有遇到很多问题?有朋友说,他也做完了很大的ASP.NET MVC,但是没遇到我那么多问题。
    更多的朋友说,他们没有我那么多东西可写,其实我想如果让我去做他们的项目,一样可写很多东西。
    关键就在这里,只有很少的问题是项目直接引起的,因为做项目是受到自身当前的条件限制,发现不了。
    还是那个悖论啊:你不学,怎么知道用的时候该用什么,怎么用好呢?

  16. xland
    *.*.*.*
    链接

    xland 2009-09-29 16:33:00

    @notlogon
    "带着做完项目的问题,思考不为是一个好方法啊!,这样更能理解。"
    这是什么意思,没看明白
    @Jeffrey Zhao
    现在总是觉得时间紧迫
    就像有人说的似的“感觉连上厕所的时间都是浪费的”

    特别希望“解决问题”和“实现功能”
    因为这两样事最能给自己带来“快感”了

    大脑被这个欲望驱动着
    学东西就特有针对性
    (不可避免的漏掉了很多基础知识,与系统的学知识相悖。)

    问题解决了,功能实现了
    难免会被人问:“诶,小子这个东西怎么搞的啊,不错嘛!”
    这个时候就又要提前准备一些理论知识
    来满足自己在别人面前炫耀的资本


    以后碰到相同的问题当然也知道怎么做
    有的时候问自己:“长知识了吗”
    确实也有积累。扪心自问的时候也得到了安慰。


    别人说:勿在浮沙筑高台
    估计就是说像我这样的一类人吧

  17. Jeffrey Chan
    *.*.*.*
    链接

    Jeffrey Chan 2009-09-29 16:36:00

    难道赵帅想自己写一个MvcHttpHandler处理遇到的逻辑?还是在原有的MvcHttpHandler上添加一些功能?对了,MvcPatch能不能svn上,一旦更新,就只有把整个项目替换了,有点不方便?只是请求。

  18. Collector
    *.*.*.*
    链接

    Collector 2009-09-29 16:42:00

    作为程序员其实是最讲究“厚积薄发”的,方方面面的知识的积累是一个长期的过程。
    有些东西在实际工作中并不一定用的上,但最终产品的质量就体现在这些积累上面。
    在这行如果太功利,是干不长的。

  19. 老赵
    admin
    链接

    老赵 2009-09-29 17:16:00

    @Jeffrey Chan
    从没想过要写自己的逻辑。
    MvcPatch一直在svn上,可以update下来编译一下。
    MvcPatch不是个扩展,而是个替换。

  20. Jeffrey Chan
    *.*.*.*
    链接

    Jeffrey Chan 2009-09-29 17:17:00

    MvcPatch你不是放在codeplex上面的?难道也在其他地方放了?

  21. 老赵
    admin
    链接

    老赵 2009-09-29 17:18:00

    @Jeffrey Chan
    就是codeplex上。

  22. Jeffrey Chan
    *.*.*.*
    链接

    Jeffrey Chan 2009-09-29 17:22:00

    那应该是我表述不正确,我想说的是,每回都要去codeplex上面下载下来,把原来的去作替换,这里挺不方便的。能不能放到code.google.com上面,然后就可以用TortoiseSVN下载或者更新?我没有发现codeplex上面的svn的地址?

  23. 老赵
    admin
    链接

    老赵 2009-09-29 17:24:00

    @Jeffrey Chan
    反正是svn,放在google code和codeplex上有什么区别呢?
    // 如果你找不到,你应该看帮助。

  24. Jeffrey Chan
    *.*.*.*
    链接

    Jeffrey Chan 2009-09-29 17:26:00

    @Jeffrey Zhao
    唯一的区别是不用去替换原来下载的mvcpatch.我就是怕你更新太快了,每回都要去下载然后替换原来的。如果放到code.google.com里面,就可以通过svn的一个只读的连接地址来获取更新的文件。

  25. 老赵
    admin
    链接

    老赵 2009-09-29 17:29:00

    @Jeffrey Chan
    我服了你了,你会用code.google.com的svn,就不会用codeplex的svn了?

  26. Jeffrey Chan
    *.*.*.*
    链接

    Jeffrey Chan 2009-09-29 17:31:00

    我错了,我的确没有找到codeplex的svn,每次都是通过下载获取的。我再去找找吧,对不起。

  27. Jeffrey Chan
    *.*.*.*
    链接

    Jeffrey Chan 2009-09-29 17:40:00

    https://MvcPatch.svn.codeplex.com/svn
    原来是这样的,谢谢赵帅了。打扰你了。

  28. winter-cn
    *.*.*.*
    链接

    winter-cn 2009-09-30 07:38:00

    xland:
    @Jeffrey Zhao
    我是先把东西做出来
    然后在分析学习它的原理的

    如果老赵也这样写文章就好了:
    1:需求说明
    2:代码实现
    3:原理分析
    4:总结扩展
    这样也多好啊(个人观点,呵呵)

    你写的趣味编程你说都是实际项目中遇到的
    但是我看完文章,学到知识了,不知道怎么用,用到哪啊!

    请原谅我的浅薄,呵呵。


    没必要可以追求怎么用 到用的时候自然想起来了

  29. 水木
    *.*.*.*
    链接

    水木 2009-09-30 09:51:00

    老赵的文章是走在技术的前沿,引领前我们,
    可是公司用到的还是少呀

  30. dsjian[未注册用户]
    *.*.*.*
    链接

    dsjian[未注册用户] 2009-10-08 10:05:00

    不错,不知道System.Web.Routing有没有开放源代码,还是要自己去reflector的。

  31. 一抹微蓝
    *.*.*.*
    链接

    一抹微蓝 2009-10-26 00:40:00

    老赵的文章隔三差五的再看一遍总会有不同的味道,哈……

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我