[MVC]ASP.NET MVC Preview 2 - 流程分析 (1)

MVC 通过在 web.config 中添加相应的 Module 来参与 ASP.NET 执行流程。

<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 事件~~~~ 嗯,PostResolveRequestCache 要比 PostMapRequestHandler 更早执行,先从它开始吧。

private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
{
  HttpContextBase context = new HttpContextWrapper2(((HttpApplication) sender).Context);
  this.PostResolveRequestCache(context);
}
public virtual void PostResolveRequestCache(HttpContextBase context)
{
  RouteData routeData = this.RouteCollection.GetRouteData(context);
  if (routeData != null)
  {
    IRouteHandler routeHandler = routeData.RouteHandler;
    if (routeHandler == null)
    {
      throw new InvalidOperationException(…);
    }
    RequestContext requestContext = new RequestContext(context, routeData);
    IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
    if (httpHandler == null)
    {
      throw new InvalidOperationException(…);
    }
    context.Items[_requestDataKey] = new RequestData { originalPath = context.Request.Path, HttpHandler = httpHandler };
    context.RewritePath("~/UrlRouting.axd");
  }
}

首先从 RouteCollection 中获取一个 RouteData 对象,RouteCollection 何许人也?

public RouteCollection RouteCollection
{
  get
  {
    if (this._routeCollection == null)
    {
      this._routeCollection = RouteTable.Routes;
    }
    return this._routeCollection;
  }
  set
  {
    this._routeCollection = value;
  }
}

说白了,所谓 RouteCollection 就是我们在 Global.asax.cs 中添加的 Route 集合。

public static void RegisterRoutes(RouteCollection routes)
{
  // Note: Change the URL to "{controller}.mvc/{action}/{id}" to enable
  // automatic support on IIS6 and IIS7 classic mode
  routes.Add(new Route("{controller}/{action}/{id}", new MvcRouteHandler())
  {
    Defaults = new RouteValueDictionary(new { action = "Index", id = "" }),
  });
  routes.Add(new Route("Default.aspx", new MvcRouteHandler())
  {
    Defaults = new RouteValueDictionary(new { controller = "Home", action = "Index", id = "" }),
  });
}

回 到上文,在获取 RoteCollection 之后,通过调用 GetRouteData(context) 返回一个 RouteData 对象(详细代码可阅读 Route.GetRouteData 方法,它通过分析当前上下文的相关请求参数,返回所需的结果对象),该对象内部包含了我们注册 Route 时的相关设置,当然就有下面所需要的 —— MvcRouteHandler。
接下来,该方法将 routeData 和上下文一起打包成 RequestContext,这应该是给后面相关处理准备的上下文环境。通过调用 MvcRouteHandler.GetHttpHandler() 方法,我们终于看到了曙光,也就是进行后续流程的关键 —— MvcHandler (有关 MvcHandler 的细节,后续章节再说)。

public class MvcRouteHandler : IRouteHandler
{
  protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
  {
    return new MvcHandler(requestContext);
  }
}

到了这一步,MVC 框架已经准备好了相应的执行场景,接下来就是修改默认的执行流程了。当然,辛苦得来的 "环境" 要选择一个合适的 "人",存储到一个合适的 "地方"。

context.Items[_requestDataKey] = new RequestData { originalPath = context.Request.Path, HttpHandler = httpHandler };

而 后的某个时间,OnApplicationPostMapRequestHandler 被执行。在 PostMapRequestHandler 中,它提取了前面预先 "埋" 下的 "坏蛋",并修改了 HttpContext.Handler,使得 MvcHandler 能继续未完的 "事业"。至于跳转之类的,就无需我再多说。

private void OnApplicationPostMapRequestHandler(object sender, EventArgs e)
{
  HttpContextBase context = new HttpContextWrapper2(((HttpApplication) sender).Context);
  this.PostMapRequestHandler(context);
}
public virtual void PostMapRequestHandler(HttpContextBase context)
{
  RequestData data = (RequestData) context.Items[_requestDataKey];
  if (data != null)
  {
    context.RewritePath(data.OriginalPath);
    context.Handler = data.HttpHandler;
  }
}

待续……
—————————-
附上流程分析图

uploads/200803/11_155627_mvc1.png

查看大图

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏