上个章节我们讲到了,可以在HttpModules初始化之前动态添加Route的方式来自定义自己的HttpHandler,最终接管请求的,那MVC是这么实现的么?本章节我们就来分析一下相关的MVC源码来验证一下我们的这个问题。
先创建一个MVC3的Web Application,选择默认的模板以便创建以后就默认包含HomeController和AccountController。我们知道MVC要先接管请求才能通过这些Controller来处理,那我们先去Global.asax.cs文件里看代码(定义接管请求要在初始化HttpModule之前,所以只能到这里来找代码(或者是利用WebActivator之类的特性来动态添加),Global.asax.cs文件里代码很少,但是有我们需要的东西,首先在Application_Start的方法里发现一行代码:
RegisterRoutes(RouteTable.Routes);
这行代码,看调用的方法名称RegisterRoutes是注册Route的意思,但是为什么参数却是全局的RouteTable.Routes集合呢?找到RegisterRoutes方法来看看具体的内容:
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults ); }
该方法有2行代码,第一行是忽略一个Route(我们先不看这个),第二行是使用MapRoute方法注册一个新的Route,默认是映射到Home Controller的Index Action上,我们可能想到了,RouteCollection(也就是刚才传入的RouteTable.Routes)的MapRoute方法就是提供我们所说的接管请求的入口,但是如何把MVC自己的HttpHandler传进去的呢?我们Go to一下这个MapRoute方法(需要安装ReShaper来查找MVC的源码),调整到了MVC的 RouteCollectionExtensions类,发现MapRoute并不是RouteCollection自带的方法,而是在MVC源码里提供的一个扩展方法,代码如下:
public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) { if (routes == null) { throw new ArgumentNullException("routes"); } if (url == null) { throw new ArgumentNullException("url"); } Route route = new Route(url, new MvcRouteHandler()) { Defaults = new RouteValueDictionary(defaults), Constraints = new RouteValueDictionary(constraints), DataTokens = new RouteValueDictionary() }; if ((namespaces != null) && (namespaces.Length > 0)) { route.DataTokens["Namespaces"] = namespaces; } routes.Add(name, route); return route; }
该代码的主要作用是new一个新的Route,然后将该Route添加到我们刚才提到的静态集合RouteTable.Routes里,以便后期查找Handler的时候使用,OK,这一步符合我们前面章节的分析。
接下来看,Route是如何new出来的,代码里的参数传入的分别是我们知道的url,以及一个MVCRouteHandler的实例,这一步也符合我们前面的分析,那我们来看一下MVCRouteHandler的GetHttpHandler方法是如何实现的获取MVCHandler的:
public class MvcRouteHandler : IRouteHandler { private IControllerFactory _controllerFactory; public MvcRouteHandler() { } public MvcRouteHandler(IControllerFactory controllerFactory) { _controllerFactory = controllerFactory; } protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) { requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext)); return new MvcHandler(requestContext); } protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext) { string controllerName = (string)requestContext.RouteData.Values["controller"]; IControllerFactory controllerFactory = _controllerFactory ?? ControllerBuilder.Current.GetControllerFactory(); return controllerFactory.GetControllerSessionBehavior(requestContext, controllerName); } #region IRouteHandler Members IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) { return GetHttpHandler(requestContext); } #endregion }
看以上的粗体代码,MvcRouteHandler在实现了IRouteHandler的GetHttpHandler,该方法调用了 MvcRouteHandler自身定义的GetHttpHandler虚方法,而在这个虚方法里我们看到了一个非常重要而又期待已久的代码——返回 MvcHandler的实例,大概看一下MvcHandler这个类,得到它就是我们所猜想的:继承于IHttpHandler接口的一个类,并且也继承了 IHttpAsyncHandler接口,我们先不管MvcHandler内部是如何实现的,但我们前面几章节的全部分析终于得到了验证,也就说在这里得到了Mvc的专用处理Handler,然后调用它的BeginProcessRequest方法进入Mvc自身的Pipeline进行处理了。
至此,我们终于弄明白了Mvc在整个ASP.NET Runtime是如何接管请求的了,也应该大概清楚整个ASP.NET Runtime的运行机制了,至于MvcHandler的实现方式,我们会在后面的很多章节逐一给大家分析每行代码,今天我们还有一个小任务,那就是:看完了Mvc的实现机制,我们能否自己来写一个自定义的HttpHandler通过Route动态注册进去,来实现我们自己的自定义扩展,我们来尝试着做一下吧。
本栏目更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/webkf/aspx/
以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索方法
, 代码
, route
, routing
, 一个
Routes
http pipeline 请求、spring mvc ajax请求、spring mvc post请求、spring mvc 异步请求、spring mvc 请求转发,以便于您获取更多的相关知识。