Controller的激活

概述

  在此系列开篇的时候介绍了MVC的生命周期 , 对于请求的处理,都是将相应的类的方法注册到HttpApplication事件中,通过事件的依次执行从而完成对请求的处理。对于MVC来说,请求是先 经过路由系统,然后由一个MvcHandler来处理的,当请求到来时,执行此MvcHandler的ProcessRequest方法(因为已将 MvcHandler类的此方法注册到HttpApplication的事件中,所以事件的执行就触发了此方法)。详细请看之前介绍MVC生命周期的两篇博客
  下面我们就以MVC声明周期为主线,来分析下MVC源码

public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState
{
protected virtual void ProcessRequest(HttpContext httpContext)
{
//使用HttpContextWrapper对HttpContext进行封装,封装的目的是为了解耦以获得可测试性.然后从RequestContext.RouteData中提取Controller名称.
HttpContextBase httpContext2 = new HttpContextWrapper(httpContext);
this.ProcessRequest(httpContext2);
} protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
IController controller;
IControllerFactory controllerFactory;
this.ProcessRequestInit(httpContext, out controller, out controllerFactory);//获取到Controler和ControllerFactory实例,并赋值给局部变量
try
{
//当前Controler对象的Action的创建与执行(执行包括:加载TempData, 创建及执行Action,处理Action返回的ActionResult ,保存TempData数据)
controller.Execute(this.RequestContext); }
finally
{
//释放当前Controler对象
controllerFactory.ReleaseController(controller);
}
}
}

Controller的激活

   从上述代码中可以看出,对Controller激活的相关的操作是通过MvcHandler类的 ProcessRequestInit 方法来执行,而执行完成后,将获取到Controller和ControllerFactory实例!也就是说这 个 this.ProcessRequestInit(httpContext, out controller, out controllerFactory) 方法才是本片博客的旨在,下面就通过这个方法的内部代码来剖析下Controller的激活的机制!

private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
//使用指定的 HTTP 上下文来添加版本标头。如:添加一个Http Header: HTTP/1.1 200 OK … X-AspNetMvc-Version: 2.0…
this.AddVersionHeader(httpContext);
this.RemoveOptionalRoutingParameters();
//RequestContext.RouteData中提取Controller名称。如:Home/Index的话,就获取到Home
string requiredString = this.RequestContext.RouteData.GetRequiredString("controller");
factory = this.ControllerBuilder.GetControllerFactory();//获取一个用于创建Controller实例的ControllerFactory.默认DefaultControllerFactory
controller = factory.CreateController(this.RequestContext, requiredString);//根据ControllerFactory创建Controller对象。 if (controller == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture,MvcResources.ControllerBuilder_FactoryReturnedNull,new object[]
{
factory.GetType(),
requiredString
}));
}
}
由于使用了out关键字,这个方法中的执行过程中所得到的值,即:赋值给ProcessRequest方法中声明的Controller和ControllerFactory

显 然,上述的代码中这两行代码是重点,代码通过执行一个全局的变量ControllerBuilder的GetControllerFactory方法得到 一个ControllerFactory,然后再通过执行此ControllerFactory的CreateController方法得到 Controller实例!

   factory = this.ControllerBuilder.GetControllerFactory();//获取一个用于创建Controller实例的ControllerFactory.默认DefaultControllerFactory
controller = factory.CreateController(this.RequestContext, requiredString);//根据ControllerFactory创建Controller对象。

下面就来了解下这两行代码:

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

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

namespace System.Web.Mvc
{
public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState
{
//省略其他成员变量
private ControllerBuilder _controllerBuilder;
internal ControllerBuilder ControllerBuilder
{
get
{
if (_controllerBuilder == null)
{
_controllerBuilder = ControllerBuilder.Current;
}
return _controllerBuilder;
}
set { _controllerBuilder = value; }
} private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
//省略其他代码
factory = ControllerBuilder.GetControllerFactory();
}
}
}
_controllerBuilder = ControllerBuilder.Current;说明ControllerBuilder是由ControllerBuilder类的静态属性Current获取的,接下来再看一下ControllerBuilder类
ControllerBuilder

   ControllerBuilder类中有一个静态字段private static ControllerBuilder _instance = new ControllerBuilder();,静态字段是在程序执行前加载的,那么由代码可知,就需要执行该类的构造函数,即执行public ControllerBuilder(): this(null),而其后的: this(null)则表示要去执执行带一个参数的构造函数 ControllerBuilder(IResolver<IControllerFactory> serviceResolver),这个构造函数中首先判断传入的参数是否为空,如果为空的话就实例化一个 SingleServiceResolver<IControllerFactory>对象(暂且理解为封装 ControllerFactory的一个类),并赋值给私有变量_serviceResolver,通过调用_serviceResolver的 Current属性来获取当前封装的ControllerFactory实例。
实例化SingleServiceResolver<IControllerFactory>对象时:

ControllerBuilder

   注意,当实例化SingleServiceResolver<IControllerFactory>时,只有第一个参数是变量,默认情况 下传入的是null,那么实例化的该SingleServiceResolver对象的Current属性就返回 DefaultControllerFactory;当调用ControllerBuilder的SetControllerFactroy方法时会对_factoryThunk 赋值一个自定义的ControllerFactory时,那么实例化的该SingleServiceResolver对象的Current属性就返回自定 义的ControllerFactory。所以,此处就是一个扩展点,我们可以自定义一个ControllerFactory,并通过 ControllerBuilder.Current.SetControllerFactory(...)方法来让程序使用自定的 ControllFatory。这里需要说明一下的是_factoryThunk是一个无参数、返回值类型为IControllerFactory的委托,而_factoryThunk()则是一个执行这个委托得到的返回值(null、自定义的ControllerFactory)。

我们说了:
  当参数为null时,该实例对象的Current属性返回的是DefaultControllerFactory
  当参数为自定义ControllerBuilder时,该实例对象的Current属性返回的是自定义的ControllerBuilder
由 于之前我们一直把SingleServiceResolver<IControllerFactory>当作是一个封装 ControllerBuilder的一个类,下面就来看看它到底是不是封装ControllerBuilder的,并且到底是如何根据第一个参数的不同 而决定其Current属性返回值的具体类不同的。

SingleServiceResolver

  此处,我们可以为SingleServiceResolver<T>下个定义,它就是一个筛选器,如果构造函数的第一个参数为null,则返回第二个参数传入的实例,如果不为空,则返回第一个参数传入的实例!

  以 上介绍了factory = this.ControllerBuilder.GetControllerFactory();中的ControllerBuilder如何实例化,并 如何返回一个ControllerFactory实例。有了ControllerFactory之后,那么就该调用ControllerFactory的 CreateController(RequestContext requestContext, string controllerName);方法(根据第二个参数通过反射实例化一个Controller,并返回)。

非重点补充

注:以上所说的ControllerFactory泛指实现了IControllerFactory接口的类;

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

   此行代码,利用上一句得到一个ControllerFactory实例,再将【请求上下文】和【要激活的Controller的字符串】作为参数来调用 ControllerFactory类的CreateController方法,以此创建Controller实例,并返回!  即:通过ControllerFactory类来完成对Controller的激活,那么对于此行代码的解析就成了对ControllerFactory 类的分析!

  因为ControllerFactory泛指实现了IControllerFactory的类,所以就从IControllerFactory接口开始介绍:

    public interface IControllerFactory
{
//获取Controller实例
IController CreateController(RequestContext requestContext, string controllerName);
//返回值为SessionStateBehavior枚举,表示请求处理过程中会话状态支持的模式
SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName);
//释放Controller实例
void ReleaseController(IController controller);
}
public enum SessionStateBehavior
{
Default,使用默认 ASP.NET 逻辑来确定请求的会话状态行为。
Required,为请求启用完全的读写会话状态行为。
ReadOnly,为请求启用只读会话状态。
Disabled 禁用会话状态。
}

  我们可以实现此IControllerFactory接 口,再通过ControllerBuilder.Current.SetControllerBuilder()添加自定义的 ControllerBuilder;然后默认情况下,MVC使用的是DefaultControllerFactory,接下来就看看 DefaultControllerFactory中是如何实现IControllerFactory接口的。

    public class DefaultControllerFactory : IControllerFactory
{
//省略其他成员
private IResolver<IControllerActivator> _activatorResolver;
private IControllerActivator _controllerActivator;
private ControllerBuilder _controllerBuilder; public DefaultControllerFactory()
: this(null, null, null)
{
}
//利用自定义的ControllerActivator时,通过在ControllerBuilder中实例化DefaultControllerFactory时出入自定义ControllerActivator为参数
public DefaultControllerFactory(IControllerActivator controllerActivator)
: this(controllerActivator, null, null)
{
} internal DefaultControllerFactory(IControllerActivator controllerActivator,
IResolver<IControllerActivator> activatorResolver, IDependencyResolver dependencyResolver)
{
//controllerActivator类才是最终通过反射创建Controller实例的
//重点:这里对判断controllerActivator的判断,只有当为空时才使用默认的DefaultControllerActivator
//所以,这里又有一个扩展,通过实现IControllerActivator接口创建自定义ControllerActivator
//在实例化DefaultControllerFactory时传入自定义ControllerActivator作为参数
if (controllerActivator != null)
{
_controllerActivator = controllerActivator;
}
else
{
//此处第一个参数是个常量且为null,所以此SingleServiceResolver<>的Current属性只能返回DefaultControllerActivator实例
_activatorResolver = activatorResolver ?? new SingleServiceResolver<IControllerActivator>(
() => null,
new DefaultControllerActivator(dependencyResolver),
"DefaultControllerFactory constructor");
}
}
//在ControllerBuilder中实例化DefaultControllerFactory时,赋值。(参见ControllerBuilder类的构造函数)
internal ControllerBuilder ControllerBuilder
{
get { return _controllerBuilder ?? ControllerBuilder.Current; }
set { _controllerBuilder = value; }
} private IControllerActivator ControllerActivator
{
get
{
//当_controllerActivator为空时,才去_activatorResolver中获取DefaultControllerActivator实例作为ControllerActivator
if (_controllerActivator != null)
{
return _controllerActivator;
}
_controllerActivator = _activatorResolver.Current;
return _controllerActivator;
}
} public virtual IController CreateController(RequestContext requestContext, string controllerName)
{
//省略其他代码
       //根据字符串【类型名】和【上下文中的命名空间】创建Controller的类型
Type controllerType = GetControllerType(requestContext, controllerName);
IController controller = GetControllerInstance(requestContext, controllerType);//根据类型创建Controller实例
return controller;
} protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
//省略其他代码
       //调用ControllerActivator实例的Create通过反射创建实例。默认为DefaultControllerActivator
return ControllerActivator.Create(requestContext, controllerType);
} }
DefaultControllerActivator

  上述代码中注释部分包含【Controller激活的步骤】和又一扩展点【创建自定ControllerActivator 】,所以略显混乱。下面我们就来用文字叙述一下这两部分:
一、根据ControllerBuilder中实例化DefaultControllerFactory时,利用的是无参数的构造函数,但是此构造函数又带着三个为null的参数执行有三个参数的构造函数,所以默认情况下私有字段_controllerActivator就是null,那么执行Current来获取ControllerActivator时,就将DefaultControllerActivator实例赋值给_controllerActivator字段,之后再调用该实例的Create方法,在方法内部利用反射创建Controller实例。
二、正如我们所知,最后是通过一个ControllerActivator的Create方法,根据参数【请求上下文】【Controller类型】来实现创建Controller实例的。所以,我们就可以通过实现IControllerActivator接口来创建自定义的ControllerActivator。创建自定义的ControllerActivator没问题,那么
如何使程序去利用自定义的ControllerActivator呢?
  答:注意DefaultControllerFactory含有三个参数的构造函数,首先会判断第一个参数controllerActivator如果不为空,则将参数赋值给私有变量_controllerActivator。当通过Current获取当前ControllerActivator时,判断 私有变量_controllerActivator是否为空,如果不为空,则直接返回。由此,我们就可以在实例化DefaultControllerFactory时为第一个参数传入自定义ControllerActivator实例,即通过实例化含一个参数DefaultControllerFactory构造函数,进而再去执行三个参数的构造函数。
又如何执行DefaultControllerFactory带一个参数的构造函数并传入自定义ControllerActivator实例作为参数呢?
   答:通过在Application_Start方法中通过ControllerBuilder的SetControllerBuilder方法的参数中 传入new DefaultControllerFactory(new MyControllerActivator())为参数。即:MyControllerActivator类是实现了 IControllerActivator接口的自定义ControllerActivator

ControllerBuilder controllerBulder = ControllerBuilder.Current;
controllerBulder.SetControllerFactory(new DefaultControllerFactory(new MyControllerActivator()) { ControllerBuilder = controllerBulder });

   以上就是第二句代码controller = factory.CreateController(this.RequestContext, requiredString);获取Controller实例的全部,其中又对发现了一个扩展点【自定义ControllerActivator】和如 何让程序使用自定义的ControllerActivator

 Controller的释放

  由本篇博客概述中的MvcHandler类中,可以看出在try finally块的fianlly中通过controllerFactory.ReleaseController(controller); 即:当前ControllerFactory的ReleseController方法来实现释放,我们就来看看默认的DefaultControllerFactory中的ReleseController方法

    public class DefaultControllerFactory : IControllerFactory
{
//省略其他成员 public virtual void ReleaseController(IController controller)
{
IDisposable disposable = controller as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
}

以上本篇博客Controller激活的全部内容!!!

 对于Controller激活的相关知识中遗留的问题有:
1、Controller类型的缓存

2、会话状态行为的控制

3、DependencyResoolver类
如有兴趣的话,对于此三部分的问题可以到Artech的博客MVC系列【How ASP.NET MVC Works】Controller激活部分学习下!

 
 
分类: MVC

Controller的激活的更多相关文章

  1. ASP.NET MVC Controller的激活

    最近抽空看了一下ASP.NET MVC的部分源码,顺带写篇文章做个笔记以便日后查看. 在UrlRoutingModule模块中,将请求处理程序映射到了MvcHandler中,因此,说起Controll ...

  2. 白话学习MVC(五)Controller的激活

    一.概述 在此系列开篇的时候介绍了MVC的生命周期 , 对于请求的处理,都是将相应的类的方法注册到HttpApplication事件中,通过事件的依次执行从而完成对请求的处理.对于MVC来说,请求是先 ...

  3. ASP.NET MVC——Controller的激活

    Controller的激活是根据在路由过程得到的Controller名称来创建对应的Controller对象.相关类如图: Controller激活的过程可通过如下序列图表示: 代码示例如下: str ...

  4. Asp.net mvc 中的 Controller 的激活

    Controller 激活是指根据路由系统解析出来的 Controller 的名称创建 控制器(Controller)的过程,这里的控制器泛指实现了 IController 接口的类型 激活过程中的核 ...

  5. Artech的MVC4框架学习——第三章controller的激活

    第一当目标controller的名称通过URL路由被解析出来后,asp.net mvc利用 ControllerBuilder 注册 ControllerFactory ,根据名称实现对目标contr ...

  6. MVC Controller的激活

    各Controller的继承关系 Controller最重要的是对Execute方法的调用,当目标Controller对象被激活后,对请求的后续处理和最终响应均是通过执行这个Execute方法来完成. ...

  7. 总体介绍ASP.NET Web API下Controller的激活与释放流程

    通过<ASP.NET Web API的Controller是如何被创建的?>我们已经对HttpController激活系统的核心对象有了深刻的了解,这些对象包括用于解析程序集和有效Http ...

  8. ASP.NET WebAPI 09 Controller的激活

    在Controller之前我们先回顾一下HttpMessageHandler通道. 在这个图中我留一个HttpContollerDispatcher没有说明.因为这个类也是继承自HttpMessage ...

  9. ASP.NET MVC4学习笔记之Controller的激活

    一. 高层相关类说明 当路由系统根据请求Url收集路由信息后,下一步就要将路由信息传给Controller激活系统,Controller激活系统负责实现了IController接口的Controlle ...

随机推荐

  1. HTML5分析实战Web存储机制(Web Storage)

    Web Storage它是Key-Value在持久性数据存储的形式.Web Storage为了克服cookie把所引起的一些限制.当数据需要严格格控制client准时,没有必要不断地发回数据serve ...

  2. Android测试流量的几种方法

    1. tcpdump + wireshark 1.1 tcpdump抓包 注意:Android设备使用tcpdump需要root权限 tcpdump是一个在Unix-like系统中通用的网络抓包工具, ...

  3. 【转】UiAutomator简要介绍

    原文地址:http://blog.csdn.net/g19920917/article/details/16131565 3.1.必备条件: 1.JDK    2.SDK(API高于15)    3. ...

  4. 【百度地图API】建立全国银行位置查询系统(四)——如何利用百度地图的数据生成自己的标注

    原文:[百度地图API]建立全国银行位置查询系统(四)--如何利用百度地图的数据生成自己的标注 摘要: 上一章留个悬念,"如果自己没有地理坐标的数据库,应该怎样制作银行的分布地图呢?&quo ...

  5. [CLR via C#]1.6 Framework类库~1.9与非托管代码的互操作性

    原文:[CLR via C#]1.6 Framework类库~1.9与非托管代码的互操作性 1.6 Framework类库 1. .NET Framework中包含了Framework类库(Frame ...

  6. PHP的MySQL扩张:MySQL数据库概述

    资源:http://www.ido321.com/1023.html 一.SQL:结构化查询语言 SQL(Structured Query Language)是高级的非过程化变成语言.专门用于查询和改 ...

  7. MySQL 升级方法指南大全

    原文:MySQL 升级方法指南大全 通常,从一个发布版本升级到另一个版本时,我们建议按照顺序来升级版本.例如,想要升级 MySQL 3.23 时,先升级到 MySQL 4.0,而不是直接升级到 MyS ...

  8. WinForm播放视频

    原文:WinForm播放视频 1背景 这几天一老友要求我做个小软件,在WinForm播放视频.印象中微软有个WM控件直接可以使用,晚上研究下 2实现方式 2.1微软草根 最简单的方式,是直接使用微软的 ...

  9. 在 MVC6 中创建 Web API

    ASP.NET 5系列教程 (六): 在 MVC6 中创建 Web API   ASP.NET 5.0 的主要目标之一是统一MVC 和 Web API 框架应用. 接下来几篇文章中您会了解以下内容: ...

  10. 通过扩展改善ASP.NET MVC的验证机制[实现篇]

    原文:通过扩展改善ASP.NET MVC的验证机制[实现篇] 在<使用篇>中我们谈到扩展的验证编程方式,并且演示了本解决方案的三大特性:消息提供机制的分离.多语言的支持和多验证规则的支持, ...