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を取得した.
????