上一章节中对路由的注册和匹配过程进行了介绍,知道了MVC的Http请求最终是交由MvcHandler处理的,而其处理过程就是对Controller的创建、执行和释放。
本章将从以下几点进一步对上面提到的三个过程进行介绍:
● MvcHandler概述
● ControllerBuilder&ControllerFactory
● DefaultControllerFactory
● Controller&ControllerBase
● Controller的执行
MvcHandler概述
MvcHandler是MVC的核心组件,用于接收并处理来自客户的MVC请求,以下是MvcHandler类型的定义:
MvcHandler实现了IHttpHandler和异步的IHttpAsyncHandler接口,这两个接口是用于处理Http请求的接口,其实这里所谓的“处理”就是根据用户请求的信息来生成一个响应信息返回到客户端。所以Mvc中也一样,通过Http请求的Head、Body等信息从中抓取需要的数据,然后将其传入Controller的Action中执行业务逻辑后,渲染一个Html模板返回至客户端显示。
它的构造需要一个RequestContext对象。而RequestContext其实是HttpContextBase(包含了HTTP请求的所有信息)和RouteData的封装,这个对象是在UrlRoutingModule中创建的,然后通过MvcRouteHandler传到了MvcHandler中。
以下是MvcHandler的处理概况图:
ControllerBuilder&ControllerFactory
MvcHandler执行的一个步骤就是初始化,其中最重要的就是创建Controller,而Controller的创建离不开ControllerBuilder和ControllerFactory,那么它们到底起到什么作用?
1. ControllerBuilder:用于获取和设置ControllerFactory,在没有设置过ControllerFactory的情况下默认获得DefaultControllerFactory。
以下是ControllerBuilder的定义:
2. ControllerFactory:它其实是一个IControllerFactory接口,专门用于创建和销毁Controller。MVC的默认实现是DefaultControllerFactory。
综上所述,ControllerBuilder用于创建ControllerFactory,而ControllerFactory用于创建Controller,而ControllerFactory的默认实现是DefaultControllerFactory。
DefaultControllerFactory
以下是DefaultControllerFactory的定义:
它除了实现IControllerFactory的方法外还有两个名为GetControllerInstance、GetControllerType的受保护的虚方法,另外构造方法有一个类型为IControllerActivator的参数。前者很容易理解,在.Net中可以通过一个类型来创建一个实例,而可以通过类型名称在程序集中找到对应的类型。所以可以想到的是两个方法分别就是根据Controller的名称获取类型然后在通过类型创建实例的方法。而后者从名称看来是Controller的激活器,那它的作用是什么呢?是用来创建Controller实例的吗?
以下是CreateController的代码,从代码中也证实了上面的猜测,Controller的创建是先根据Controller名称查找类型,然后通过类型创建Controller实例。
1. Controller类型的查找:
1). 命名空间的处理:路由中的命名空间、ControllerBuilder中的命名空间、无命名空间;三种命名空间从前到后依次以其值来作为命名空间匹配,直到找到对应Controller的类型。换句话说如果路由对象和Controller Builder都设置了命名空间,那么先根据路由对象的去查找,如果找不到再使用ControllerBuilder设置的命名空间,如果仍然没有就不使用命名空间来进行匹配。
2). Controller类型缓存数据处理:为了提高MVC的性能,在通过缓存的形式在第一次查找Controller类型的时候遍历所有依赖程序集中的IController类型生成一个名称为“MVC-ControllerTypeCache.xml”缓存文件(由ControllerTypeCache类型完成),以下是缓存文件格式:
注:该缓存路径一般在systemroot\Microsoft .NET\Framework\versionNumber\Temporary ASP.NET Files\{app name}\..\..\UserCache或systemroot\Microsoft .NET\Framework\versionNumber\Temporary ASP.NET Files\root\..\..\UserCache目录下,但是可能由于Web宿主不同或环境配置不同而不同,但是可以在代码中通过HttpRuntime.CodegenDir属性找到。另外还有一个缓存文件是对Area注册的缓存,名称为MVC-AreaRegistrationTypeCache.xml。
3). 类型的匹配:Controller的类型匹配相对简单,它使用{NameSpace}.{ControllerName}的形式在上面文件的数据结构中匹配。
2. Controller的创建:
1). 判断Controller类型是否是继承于IController。
2). 通过ControllerActivator创建Controller实例。
3. 关于ControllerActivator:用于Controller的创建,在MVC中有一个DefaultControllerActivator存在于DefaultControllerFactory中,它用于通过.Net中的Activator对象或依赖解析器创建Controller实例。
Controller&ControllerBase
在开发中MVC控制器的时候,一般以Controller类型作为基类,通过继承的方式来完成。这样可以轻松的获得Controller基类提供的功能。而Controller其实是继承至ControllerBase抽象类,ControllerBase中提供了MVC中最核心的Execute方法和ExecuteCore抽象方法以及必要的一些属性如TempDataDictionary以及ViewDataDictionary等,使用典型的模板模式规定了Controller类型的框架。
1. ControllerBase:定义了Controller的核心框架
2. Controller:实现了ASP.NET MVC中控制器的执行逻辑,以及附加功能,如验证、异常处理、事件处理(Action执行事件、验证事件等)、跳转、多种返回类型(包括但不限于MVC页面、Json数据、文件、普通内容)等。
注:由于Controller定义代码太多,所以不在放出,大家可以在VS中查看。
Controller的执行
上面提到过ControllerBase是整个Controller类结构的模板,所以在ASP.NET MVC调用Controller执行时实际上是调用的ControllerBase类型的Execute方法,而该方法内部实际上调用的是子类的ExecuteCore方法,以下是Controller类型的ExecuteCore:
从代码可以看出Controller的执行“很”简单,只有四步:加载临时数据、获取Action、执行Action、保存临时数据。
注:本章不再对Action的执行进行介绍,因为Action的执行包含了很多内容,比如过滤器的执行、模型的绑定等,所以这些内容会在后续讲解。
小结
本章以MvcHandler的执行为入口,以MVC控制器的创建、执行为流程,介绍了其相关的重要对象和执行逻辑。更多内容请关注后续文章。