MVC 依赖 System.Web.Routing 处理请求路径解析,也就是说整个流程的起始是由 System.Web.Routing.UrlRoutingModule 开始的。 

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

那么我们就看看这个 UrlRoutingModule 内部都做了什么。 

public class UrlRoutingModule : IHttpModule 

protected virtual void Init(HttpApplication application) 

application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache); 
application.PostMapRequestHandler += new EventHandler(this.OnApplicationPostMapRequestHandler); 



订阅了两个 HttpApplication 事件。在 ASP.NET 应用程序生命周期中 PostResolveRequestCache 会在 PostMapRequestHandler 之前触发,最后是 IHttpHandler.ProcessRequest() 完成最终的请求处理。 

通过对请求上下文进行包装,进一步进行处理。 

public class UrlRoutingModule : IHttpModule 

private void OnApplicationPostMapRequestHandler(object sender, EventArgs e) 

HttpContextBase context = new HttpContextWrapper(((HttpApplication) sender).Context); 
this.PostMapRequestHandler(context); 


private void OnApplicationPostResolveRequestCache(object sender, EventArgs e) 

HttpContextBase context = new HttpContextWrapper(((HttpApplication) sender).Context); 
this.PostResolveRequestCache(context); 



首先, PostResolveRequestCache 被执行。 

public class UrlRoutingModule : IHttpModule 

public virtual void PostResolveRequestCache(HttpContextBase context) 

RouteData routeData = this.RouteCollection.GetRouteData(context); 

if (routeData != null) 

IRouteHandler routeHandler = routeData.RouteHandler; 

... 

if (!(routeHandler is StopRoutingHandler)) 

RequestContext requestContext = new RequestContext(context, routeData); 
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); 

... 

RequestData data2 = new RequestData(); 
data2.OriginalPath = context.Request.Path; 
data2.HttpHandler = httpHandler; 
context.Items[_requestDataKey] = data2; 
context.RewritePath("~/UrlRouting.axd"); 





RouteCollection 实际是对 RouteTable.Routes 的引用。 

public class UrlRoutingModule : IHttpModule 

public RouteCollection RouteCollection 

get 

if (this._routeCollection == null) 

this._routeCollection = RouteTable.Routes; 

return this._routeCollection; 

set 

this._routeCollection = value; 




好吗,又跳了一回。 

public class RouteTable 

private static RouteCollection _instance = new RouteCollection(); 

public static RouteCollection Routes 

get 

return _instance; 



这时候,我们要提及 Global.asax.cs 中的代码。 

public class MvcApplication : System.Web.HttpApplication 

public static void RegisterRoutes(RouteCollection routes) 

routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

routes.MapRoute( 
"Default", 
"{controller}/{action}/{id}", 
new { controller = "Home", action = "Index", id = "" } 
); 



protected void Application_Start() 

RegisterRoutes(RouteTable.Routes); 



IgnoreRoute 和 MapRoute 都是 System.Web.Mvc.dll 中提供的扩展方法。 

public static class RouteCollectionExtensions 

public static void IgnoreRoute(this RouteCollection routes, string url); 
... 
public static Route MapRoute(this RouteCollection routes, string name, string url); 
... 


唯一需要注意的是方法内部一个细节,其注册的 IHttpHandler 是 MvcRouteHandler。 

public static class RouteCollectionExtensions 

public static Route MapRoute(this RouteCollection routes, string name, ...) 

Route <>g__initLocal1 = new Route(url, new MvcRouteHandler()); 
<>g__initLocal1.Defaults = new RouteValueDictionary(defaults); 
<>g__initLocal1.Constraints = new RouteValueDictionary(constraints); 
Route route = <>g__initLocal1; 

if ((namespaces != null) && (namespaces.Length > 0)) 

route.DataTokens = new RouteValueDictionary(); 
route.DataTokens["Namespaces"] = namespaces; 


routes.Add(name, route); 
return route; 


public static void IgnoreRoute(this RouteCollection routes, string url, object constraints) 

IgnoreRouteInternal <>g__initLocal0 = new IgnoreRouteInternal(url); 
<>g__initLocal0.Constraints = new RouteValueDictionary(constraints); 
IgnoreRouteInternal route = <>g__initLocal0; 
routes.Add(route); 


private sealed class IgnoreRouteInternal : Route 

public IgnoreRouteInternal(string url) : base(url, new StopRoutingHandler()) { } 



public class MvcRouteHandler : IRouteHandler 

protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext); 
IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext); 


好了,回到 UrlRoutingModule.PostResolveRequestCache。 

public class UrlRoutingModule : IHttpModule 

public virtual void PostResolveRequestCache(HttpContextBase context) 

RouteData routeData = this.RouteCollection.GetRouteData(context); 

if (routeData != null) 

IRouteHandler routeHandler = routeData.RouteHandler; 

... 

if (!(routeHandler is StopRoutingHandler)) 

RequestContext requestContext = new RequestContext(context, routeData); 
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); 

... 

RequestData data2 = new RequestData(); 
data2.OriginalPath = context.Request.Path; 
data2.HttpHandler = httpHandler; 

context.Items[_requestDataKey] = data2; 
context.RewritePath("~/UrlRouting.axd"); 




在获取 RouteData 和 MvcRouteHandler 后,调用 MvcRouteHandler.GetHttpHandler() 获取 IHttpHandler。 

public class MvcRouteHandler : IRouteHandler 

protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) 

return new MvcHandler(requestContext); 


IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) 

return this.GetHttpHandler(requestContext); 



好!MvcHandler 出现了,这意味着执行流程从 System.Web.Routing 转到 System.Web.Mvc 的契机出现了。UrlRoutingModule.PostResolveRequestCache() 的最后将相关请求参数保存到上下文中,还有一行奇怪的代码,看看我们从 Microsoft Symbol Server 下载的源代码会有什么说明。 

具体步骤: 

1. 首先添加 PostResolveRequestCache 断点 (我们可以为没有源代码的方法设置断点)。

烈火网(liehuo.net)提示:点击新窗口预览!

2. 然后下载符号文件。 

烈火网(liehuo.net)提示:点击新窗口预览!
3. 打开源代码。 

烈火网(liehuo.net)提示:点击新窗口预览!

好了,看看原作者如何说的。 

public virtual void PostResolveRequestCache(HttpContextBase context) 

// Save data to be used later in pipeline 
context.Items[_requestDataKey] = new RequestData() 

OriginalPath = context.Request.Path, 
HttpHandler = httpHandler 
}; 

// Rewrite path to something registered as a managed handler in IIS. This is necessary so IIS7 will 
// execute our managed handler (instead of say the static file handler). 
context.RewritePath("~/UrlRouting.axd"); 

不扯闲话了,我们继续执行流程。依照 ASP.NET HttpApplication 事件顺序,接下来 UrlRoutingModule.PostMapRequestHandler() 会被执行。 

public class UrlRoutingModule : IHttpModule 

public virtual void PostMapRequestHandler(HttpContextBase context) 

RequestData data = (RequestData) context.Items[_requestDataKey]; 
if (data != null) 

context.RewritePath(data.OriginalPath); 
context.Handler = data.HttpHandler; 




RequestData data 显然就是 PostResolveRequestCache() 保存的数据。通过将 HttpContext.Handler 设置为 MvcHandler,使得后续执行得以进行。对了,原作者对于这个方法的 RewritePath 也有说明。 

public virtual void PostMapRequestHandler(HttpContextBase context) 

RequestData requestData = (RequestData)context.Items[_requestDataKey]; 

if (requestData != null) 

// Rewrite the path back to its original value, so the request handler only sees the original path. 
context.RewritePath(requestData.OriginalPath); 

// Set Context.Handler to the IHttpHandler determined earlier in the pipeline. 
context.Handler = requestData.HttpHandler; 



好了,有关 System.Web.Routing 的流程分析就到这了。

烈火网(liehuo.net)提示:点击新窗口预览!

posted on 2009-10-25 16:18  shawnliu  阅读(444)  评论(0编辑  收藏  举报