004. Asp.Net RoutingとMVCの2:ControllerとActionのアクティブ化を要求する

25295 ワード


 
前回はリクエストが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 controller Factory)では,この方法の内部コードにより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));
 
 
以下は、工場をどのように取得するか、工場がどのように名前に基づいてコントロールタイプのインスタンスを作成するかを明らかにしていません.
 
明らかに、上記のコードには2行の重要なコードがあります.
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インスタンスを作成して返します.
 
 
 
 
 
 
これで,要求されたルーティングデータからcontrollerrName,またcontrollerNameを用いて,ControllerFactoryにより真のControllerを取得した.
????