asp.net与MVC4的路由原理和过程【学习笔记】

当IIS收到一个http请求,把请求信息发给对应的HttpModel(实际是实现类UrlRoutingModule),在HttpModel中会注册HttpApplication 类中的PostResolveRequestCache事件,通过此事件来动态选择映射HttpHandler处理程序。通过匹配到的RouteData类的RouteHandler属性得到IRouteHandler对象(MVC4是MvcRouteHandler、asp.net原生的是PageRouteHandler),通过这个对象的GetHttpHandler方法就可以得到HttpHandler处理程序。具体代码如下:

public virtual void PostResolveRequestCache(object sender, EventArgs e) {

   HttpApplication app = (HttpApplication)sender;

       HttpContextBase context = new HttpContextWrapper(app.Context);
       //详细见附1
       RouteData routeData = RouteCollection.GetRouteData(context);
       if (routeData == null) {
            return;
       }
       //详细见附1
       IRouteHandler routeHandler = routeData.RouteHandler;
       if (routeHandler is StopRoutingHandler) {
           return;
       }
       RequestContext requestContext = new RequestContext(context, routeData);
       context.Request.RequestContext = requestContext;
       IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); 
       if (httpHandler is UrlAuthFailureHandler) {
           if (FormsAuthenticationModule.FormsAuthRequired) {
                 UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this);
            return;
          }
          else {
           throw new HttpException(401, SR.GetString(SR.Assess_Denied_Description3));
          }
      }
      context.RemapHandler(httpHandler);//动态指定HttpHandler
 }

附1:

RouteCollection.GetHttpHandler方法获取匹配当前路由信息的RouteData,此方法是循环遍历RouteCollection集合并调用集合中RouteBase(实现类为Route)的GetRouteData方法,并返回第一个不为Null的Roudata。Roudata实在RoudataBase的GetRouteData方法中被创建的,详见如下代码:

 public override RouteData GetRouteData(HttpContextBase httpContext) {
     string requestPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;
     RouteValueDictionary values = _parsedRoute.Match(requestPath, Defaults);
     if (values == null) {
          return null;
     }
    //为Roudata指定IRouteHandler对象
    RouteData routeData = new RouteData(this, RouteHandler);     
if (!ProcessConstraints(httpContext, values, RouteDirection.IncomingRequest)) {
          return null;
     }
     foreach (var value in values) {
          routeData.Values.Add(value.Key, value.Value);
     }
     if (DataTokens != null) {
          foreach (var prop in DataTokens) {
             routeData.DataTokens[prop.Key] = prop.Value;
          }
     }
    return routeData;
 }
 
public class RouteData {
        private IRouteHandler _routeHandler; 
        public RouteData() {
        }
        public RouteData(RouteBase route, IRouteHandler routeHandler) {
            Route = route;
            RouteHandler = routeHandler;
        }
//更多代码
}

MVC4:动态指定到HttpHandler后,就是处理Controller的创建和Action的执行了

HttpHandler根据Routedata获取到Controller的名称,然后通过ControllerBuilder的静态方法GetControllerFactory获取IControllerFactory的实现类(默认是DefaultControllerFactory )来创建请求的IController的实现类的实例。最后执行IController的Execute方法并传入请求上下文,方法Execute实现在System.Web.Mvc.ControllerBase这个抽象类中,Execute最终调用的是System.Web.Mvc.Controller中的ExecuteCore方法,ExecuteCore方法主要是保存TempData然后根据路由数据调用执行Action。代码如下:

protected override void ExecuteCore()
{
   PossiblyLoadTempData();
   try
   {
      string actionName = GetActionName(RouteData);
//ActionInvoker是System.Web.Mvc.Controller的属性,该属性是一个返回类型为IActionInvoker的action执行器 if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) { HandleUnknownAction(actionName); } } finally { PossiblySaveTempData(); } }