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

时间:2023-03-09 03:18:34
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

MVCHander –>  ProcessRequest()

xxxxxController\ControllerFactory

IController.Excute();

ControllerBase.Excute().ExcuteCore()

Controller.ExecuteCore()  { . GetActionName  ;  IActionInvoker.InvokeAction() }

IActionInvoker.InvokeAction() {

get methodInfo  //sys

处理参数  // BindModel

methodInfo.invoke();//sys

}

1.定义Model

2.Model 里注册事件 ,附加 routerHander

3。routerHander 里 返回真正的  hander

4. hander.ProcessRequest(  HttpCotent content )

{

get Controller type

get Action(Method)  methodinfo

var invokeResult = method.Invoke(controllerContext.Controller, parameters.ToArray())
            //as ActionResult;

controllerContext.RequestContext.HttpContext.Response.Write(invokeResult);

}

一、mvc 下 url 的各种玩法

ip/home/index/3

ip/3

二、

//    parameters.Add(this.ModelBinder.BindModel(controllerContext, parameter.Name, parameter.ParameterType));

以下是没有搞清楚的内容,如何获取工厂,工厂又如何依据名字,创建一个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。

????