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;
}
}
}
2. 然后下载符号文件。
3. 打开源代码。
好了,看看原作者如何说的。
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 的流程分析就到这了。
请发表评论