ASP.NET MVC 控制器激活(一)

前言

在路由的篇章中讲解了路由的作用,讲着讲着就到了控制器部分了,从本篇开始来讲解MVC中的控制器,控制器是怎么来的?MVC框架对它做了什么?以及前面有的篇幅所留的疑问将会在这部分里解决掉。

对于控制器激活的总结

总的来说控制器的激活过程有这么几个步骤(部分):

1.根据当前路由信息获取控制器名称

2.获取当前系统的控制器工厂(用来生成控制器)

2.1 据控制器名称生成和当前系统的请求上下文参数生成控制器类型(Type

2.1.1 根据当前的路由信息判断选择控制器所在命名空间

2.1.2 返回控制器类型(Type)

2.2 根据控制器类型(Type)请求上下文参数生成控制器类型(IController)

2.3 返回控制器类型(IController)

3.获取由控制器工厂生成的控制器(IController)

4.执行IController.Execute()

控制器的由来

前面都有讲到MVC的入口在Module中,具体是在注册路由的时候,默认的注册MvcHandler作为请求处理类型,而控制器的就是在这里生产出来的,为什么说是生产?因为系统预先实现了一个控制器工厂类DefaultControllerFactory(如下的代码结构),在控制器生成到执行的这个过程里涉及到众多的类型和控制器的对象模型,这些内容在后面篇幅会一一讲解。

DefaultControllerFactory类型的结构:

public class DefaultControllerFactory: IControllerFactory {
    public DefaultControllerFactory();
    public DefaultControllerFactory(IControllerActivator controllerActivator);

    public virtual IController CreateController(RequestContext requestContext, string controllerName);
    protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType);
    protected internal virtual SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType);
    protected internal virtual Type GetControllerType(RequestContext requestContext, string controllerName);
    public virtual void ReleaseController(IController controller);
}

本篇先将上面总结中的2.1.2之前的部分粗略的讲解一下,请先看如下图:

如上图,这里先要说的是控制器类型缓存对象ControllerTypeCache,ControllerTypeCache加载所有实现了IController接口的公共类并缓存在MVC-ControllerTypeCache.xml文件里。当然了这些都是框架所做的,我们只需了解一下,学习其中的思想就行了。

在请求到达默认请求处理程序的时候,由默认的控制器工厂DefaultControllerFactory来根据RouteData的DataToken【NameSpaces】里的定义的命名空间和Values【controller】的控制器名称来进行判断,具体怎么判断的是由ControllerTypeCache对象来查询匹配的。

先根据控制器名称查询缓存中是否有对应此名称的控制器,如果有则存放在 ILookup<string, Type>类型对象中,然后根据RouteData的DataToken【NameSpaces】里的定义的命名空间来和ILookup<string, Type>对象中的控制器类型所在命名空间进行比对,如果是相同的则添加此类型到返回集合,如果不相同则继续用RouteData的DataToken【NameSpaces】剩下的命名空间值挨个的进行比对。

根据返回的类型集合,如果总数为0返回空,总数为1返回此集合中的类型,如果大于1则会引发CreateAmbiguousControllerException类型的异常。

在此时DefaultControllerFactory中已经获取到了控制器类型(Type)。

在总结中2.2所指部分为IControllerActivator接口类型的实现。

     // 摘要:
     //     对使用依赖项注入实例化控制器的方式进行精细控制。
     public interface IControllerActivator
     {
         // 摘要:
         //     在类中实现时创建控制器。
         //
         // 参数:
         //   requestContext:
         //     请求上下文。
         //
         //   controllerType:
         //     控制器类型。
         //
         // 返回结果:
         //     创建的控制器。
         IController Create(RequestContext requestContext, Type controllerType);

这部分的实现,可以注入到控制器工厂,而实现的内部依然有可扩展注入的地方,在MVC框架中有默认的实现,我们先来看一下2.2部分之后的实现概念图:

获取到了Controller的Type过后,DefaultControllerFactory就可以根据Type来创建Controller,然而在MVC框架的设计中,【根据ControllerType创建Controller的方式】是不会放在DefaultControllerFactory中的,而是通过MVC框架中实现了IControllerActivator接口类型的默认实现类DefaultControllerActivator类型来进行创建IController的,而在DefaultControllerActivator中又是通过DependencyResolver类型来创建一个IDependencyResolver接口的默认实现类来实现的。

在IDependencyResolver接口中,有个GetService()方法,这个方法就是最终要创建类型所用到的方式,也可以自定义来实现,这也是扩展点之一。说回接口类型,MVC中有个默认的实现了IDependencyResolver接口的类型DefaultDependencyResolver,在DefaultDependencyResolver类型中GetService()方法的默认实现方式Activator.CreateInstance(serviceType);也就是正常通过反射来创建类型的。

看一下由Handler到Icontroller的一个过程图:

上面的这些以及前面篇幅所讲,都是MVC默认实现的方式,每个部分都可以自定义来扩展,MvcHandler、DefaultControllerFactory、DefaultDependencyResolver等等这些类型。

会在后面的篇幅中说明在激活控制器的过程中所有可注入扩展点的。

ASP.NET MVC 学习