上篇讲到 请求到达 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。
????
004. Asp.Net Routing与MVC 之二: 请求如何激活Controller和Action