首页 > 代码库 > 004. Asp.Net Routing与MVC 之二: 请求如何激活Controller和Action

004. Asp.Net Routing与MVC 之二: 请求如何激活Controller和Action

 

 

上篇讲到 请求到达 MvcRouteHandler ,并且透过 IRouteHandler.GetHttpHandler 获取到了真正的处理程序 MvcHandler

这次我们看看,MvcHandler是如何依据请求,来激活对应的controller和Action来处理请求的。

 

一、先看看MvcHandler 的核心内容

   1: public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState
   2: {
   3:     protected virtual void ProcessRequest(HttpContext httpContext)
   4:     {
   5:         //使用HttpContextWrapper对HttpContext进行封装,封装的目的是为了解耦以获得可测试性.然后从RequestContext.RouteData中提取Controller名称.
   6:         HttpContextBase httpContext2 = new HttpContextWrapper(httpContext);
   7:         this.ProcessRequest(httpContext2);
   8:     }
   9:     
  10:     protected internal virtual void ProcessRequest(HttpContextBase httpContext)
  11:     {
  12:         IController controller;
  13:         IControllerFactory controllerFactory;
  14:         this.ProcessRequestInit(httpContext, out controller, out controllerFactory);//获取到Controler和ControllerFactory实例,并赋值给局部变量
  15:         try
  16:         {
  17:           //Action的调用,下一篇介绍
  18:                 //当前Controler对象的Action的创建与执行(执行包括:加载TempData, 创建及执行Action,处理Action返回的ActionResult ,保存TempData数据)
  19:                 controller.Execute(this.RequestContext);
  20:                 
  21:         }
  22:         finally
  23:         {
  24:             //释放当前Controler对象
  25:             controllerFactory.ReleaseController(controller); 
  26:         }
  27:     }
  28: }

 

二、Controller的激活

从上述代码中可以看出,对Controller激活的相关的操作是通过MvcHandler类的 ProcessRequestInit 方法来执行,而执行完成后,将获取到Controller和ControllerFactory实例。

this.ProcessRequestInit(httpContext, out controller, out controllerFactory) ,下面就通过这个方法的内部代码来剖析下Controller的激活的机制

   1: private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
   2: {
   3:  
   4:             // If request validation has already been enabled, make it lazy. This allows attributes like [HttpPost] (which looks
   5:             // at Request.Form) to work correctly without triggering full validation.
   6:             // Tolerate null HttpContext for testing.
   7:             //看不明白
   8:             HttpContext currentContext = HttpContext.Current;
   9:             if (currentContext != null)
  10:             {
  11:                 bool? isRequestValidationEnabled = ValidationUtility.IsValidationEnabled(currentContext);
  12:                 if (isRequestValidationEnabled == true)
  13:                 {
  14:                     ValidationUtility.EnableDynamicValidation(currentContext);
  15:                 }
  16:             }
  17:             //为响应添加特定的头标示:MvcVersionHeaderName, MvcVersion
  18:             AddVersionHeader(httpContext);
  19:             //从当前请求的路由集合中,移除可选的路由参数
  20:             RemoveOptionalRoutingParameters();
  21:  
  22:             // Get the controller type
  23:             //从当前请求的路由集合中,检索名为"controller"参数的值
  24:             string controllerName = RequestContext.RouteData.GetRequiredString("controller");
  25:  
  26:             // Instantiate the controller and call Execute
  27:             //通过 ControllerBuilder 获取 当前的 controllFactory 控制器工厂
  28:             factory = ControllerBuilder.GetControllerFactory();
  29:             //通过controllFactory 控制器工厂 ,以及前边获取到的 controllerName,构建一个 controller类型实例。
  30:             controller = factory.CreateController(RequestContext, controllerName);
  31:             if (controller == null)
  32:             {
  33:                 throw new InvalidOperationException(
  34:                     String.Format(
  35:                         CultureInfo.CurrentCulture,
  36:                         MvcResources.ControllerBuilder_FactoryReturnedNull,
  37:                         factory.GetType(),
  38:                         controllerName));
  39:             }
  40: }
  41:  

 

由于使用了out关键字,这个方法中的执行过程中所得到的值,即:赋值给ProcessRequest方法中声明的Controller和ControllerFactory

 

以下是没有搞清楚的内容,如何获取工厂,工厂又如何依据名字,创建一个controller类型实例。

 

显然,上述的代码中有两行重要代码:

1、factory = this.ControllerBuilder.GetControllerFactory();

    this.ControllerBuilder是MvcHandler类的一个属性,属性返回的是MvcHandler类声明的一个 ControllerBuilder类型的字段,属性在返回时会判断当前字段是否为空,如果为空,则调用ControllerBuilder类的静态属性 Current字段,来获取一个ControllerBuilder实例。

接下来再看一下ControllerBuilder类
   1: namespace System.Web.Mvc
   2: {
   3:     public class ControllerBuilder
   4:     {
   5:         //声明静态字段,执行此类的构造函数
   6:         private static ControllerBuilder _instance = new ControllerBuilder();
   7:  
   8:         private Func<IControllerFactory> _factoryThunk = () => null;
   9:         private HashSet<string> _namespaces = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
  10:  
  11:         //暂且理解为是封装ControllerFactory的一个类,通过该类的Current属性来获取当前封装的ControllerFactory实例
  12:         private IResolver<IControllerFactory> _serviceResolver;
  13:  
  14:         public ControllerBuilder()
  15:             : this(null) //: this(null)表示执行带一个参数的构造函数,并且传入的参数为Null
  16:         {
  17:         }
  18:  
  19:         internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver)
  20:         {
  21:             //如果传入的参数为null,则实例化一个SingleServiceResolver类并赋值给私有字段_serviceResolver。
  22:             _serviceResolver = serviceResolver ?? new SingleServiceResolver<IControllerFactory>(
  23:                                                       () => _factoryThunk(),
  24:                                                       new DefaultControllerFactory { ControllerBuilder = this },
  25:                                                       "ControllerBuilder.GetControllerFactory");
  26:         }
  27:  
  28:         public static ControllerBuilder Current
  29:         {
  30:             //获取Controller实例
  31:             get { return _instance; }
  32:         }
  33:  
  34:         public HashSet<string> DefaultNamespaces
  35:         {
  36:             get { return _namespaces; }
  37:         }
  38:  
  39:         [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Calling method multiple times might return different objects.")]
  40:         public IControllerFactory GetControllerFactory()
  41:         {
  42:             //获取ControllerFactory实例
  43:             return _serviceResolver.Current;
  44:         }
  45:  
  46:         public void SetControllerFactory(IControllerFactory controllerFactory)
  47:         {
  48:             if (controllerFactory == null)
  49:             {
  50:                 throw new ArgumentNullException("controllerFactory");
  51:             }
  52:  
  53:             _factoryThunk = () => controllerFactory;
  54:         }
  55:  
  56:         public void SetControllerFactory(Type controllerFactoryType)
  57:         {
  58:             if (controllerFactoryType == null)
  59:             {
  60:                 throw new ArgumentNullException("controllerFactoryType");
  61:             }
  62:             if (!typeof(IControllerFactory).IsAssignableFrom(controllerFactoryType))
  63:             {
  64:                 throw new ArgumentException(
  65:                     String.Format(
  66:                         CultureInfo.CurrentCulture,
  67:                         MvcResources.ControllerBuilder_MissingIControllerFactory,
  68:                         controllerFactoryType),
  69:                     "controllerFactoryType");
  70:             }
  71:  
  72:             _factoryThunk = delegate
  73:             {
  74:                 try
  75:                 {
  76:                     return (IControllerFactory)Activator.CreateInstance(controllerFactoryType);
  77:                 }
  78:                 catch (Exception ex)
  79:                 {
  80:                     throw new InvalidOperationException(
  81:                         String.Format(
  82:                             CultureInfo.CurrentCulture,
  83:                             MvcResources.ControllerBuilder_ErrorCreatingControllerFactory,
  84:                             controllerFactoryType),
  85:                         ex);
  86:                 }
  87:             };
  88:         }
  89:     }
  90: }

 

 

2、controller = factory.CreateController(this.RequestContext, controllername);

   此行代码,利用上一句得到一个ControllerFactory实例。将 RequestContext 和Controllername作为参数来调用 ControllerFactory类的CreateController方法,以此创建Controller实例并返回。

 

至此,我们从请求的 路由数据中,得到 controllerName,又用controllerName,通过 ControllerFactory  获取到了真正的 Controller。

????