.NET/ASP.NET MVC Controller 控制器(深刻解析控制器运行原理)

阅读目录:html

  • 1.开篇介绍
  • 2.ASP.NETMVC Controller 控制器的入口(Controller的执行流程)
  • 3.ASP.NETMVC Controller 控制器的入口(Controller的继承体系)
  • 4.ASP.NETMVC IController Factory 控制器工厂(Controller的建立)

1】开篇介绍

通过前一篇文章.NET/ASP.NET Routing路由(深刻解析路由系统架构原理) 的讲解,咱们对ASP.NETRouting路由系统的整个运行机制有了一个基本的了解;当咱们能清楚的知道Url是如何被解析成RouteData对象时,下面就是这些路由数据是如何被后面的应用框架所使用的,而通往应用框架的入口是MvcRouteHandler对象;编程

这篇文章将继续讲解经过路由后的ASP.NETMVC Controller控制器是如何被加载、激活而且执行的;跟控制器相关的一套对象模型是被MvcHandler对象做为源头调用起来的,也就是说,当咱们穿过UrlRoutingModule对象后,而且成功的获取到应用框架配置的路由数据后,下面将进入IHttpHandler接口,而这个接口真是咱们初始化RouteData对象时设定的应用框架入口,ASP.NETMVC所使用的是MvcHandler对象;缓存

MvcRouteHandler对象是UrlRoutingModuleMvcHandler对象的链接器,只有MvcRouteHandler对象能成功执行后,方能进入到MvcHandler对象中,后续的一切运转才能顺利执行;服务器

2】ASP.NETMVC Controller 控制器的入口(Controller的执行流程)

在系统刚启动的时候,也就是在Global.asax.cs文件里面咱们配置了Http客户端请求服务器的Url模板;在路由解析模块(UrlRoutingModule)里面,它将经过字符串级别的操做,解析出咱们Url模板中的{Controller}/{Action}等的占位符变量;因此这个时候Controller的概念对咱们来讲还只是一个字符串而已,而到了目前的这个Controller控制器解析的位置其实已经和路由基本不要紧了,由于咱们穿过了路由模块到达了Controller解析的环节;Controller解析已经属于ASP.NETMVC应用框架的范围,咱们能够简单的将路由解析(UrlRoutingModule)的过程视为将请求的Url(含有数据的Url)与咱们配置的Url模板进行模式匹配的过程,得出匹配后的Url数据(RouteData),而后将Url数据而且连同当前请求上下文一块儿封装成RequestContext对象(RouteData、HttpContextBase)传入到Controller解析的环节,也就是MvcHandler中,做为MvcHandler构造函数的参数;架构

当MvcHandler接管控制权以后它须要准备好对Controller的解析和执行,可是Controller并发一个简单的对象,它有一个复杂的继承体系和使用方式,缘由在于它须要协调多方面的工做因此变的有很复杂;并发

根据MVC的架构模式理论便知道Controller是协调Model与View的中间纽带,它既要管理好Model的执行,也要管理好View的呈现;而本来MVC的架构模式提出的背景是在WinFrom的状况下,也就是传统C/S结构的系统;WinFrom结构的系统有一个好处就是它的执行很方便,从View的展示收集数据到Controller的调度执行Model会容易完成,可是ASP.NETMVC是创建在ASP.NET WEB背景之下的MVC模式框架,因此这个时候对Controller的激活会变的至关麻烦,由于在传输过程当中Controller已是字符串形式,若是是在C/S结构中那么Controller对于每次处理同样的View不会每次都进行激活;既然每次都须要激活就须要进行缓存策略,缓存策略只是Controller中的一个关键点,须要明白的是Controller的确须要作不少事情;框架

图1:ide

根据上图的执行顺序,能看出Controller控制器扮演着一个很重要的角色,全部的执行、返回值、视图呈现均须要经过它来管理调度;固然本章的重点是搞清楚此图中的第一环节,Controller是如何被加载激活的,这里面将涉及到众多的辅助对象模型,好比:ControllerFactory控制器工厂,而控制器工厂又将借助ControllerTypeCache来缓存Controller对象,而ConrollerTypeCache又将借助TypeCacheSerializer来对Controller缓存文件的序列化;函数

3.ASP.NETMVC Controller 控制器的入口(Controller的继承体系)

Controller控制器既然扮演着重要的角色,那么它就不会是一个简单的对象结构,它有着一个复杂的继承体系和对象模型支撑它来完成这些艰巨的任务;Controller要想可以运行起来,就须要搞清楚它有哪些执行入口,而须要知道它有哪些执行入口咱们就须要搞清楚它的继承体系;入口的最高层抽象在哪一层,这样咱们才能触类旁通的扩展Controller的众多重要的功能;ui

首先咱们了解到Controller的顶层抽象是IController接口,而后接着是ControllerBase抽象类实现了这个接口,而做为顶层抽象的实现ControllerBase完成了从IController接口继承下来的方法;

1 public interface IController {
2     void Execute(RequestContext requestContext);
3 } 

经过该代码段能够看出,Controller的执行须要一个RequestContext对象,而这个对象真是UrlRoutingModule环节所完成的结果,RequestContext对象内部封装了在Request阶段所得到的请求数据,里面包括了跟Http相关的请求上下文(HttpContextBase),最重要的是路由数据对象(RouteData);而控制器的执行必须须要RouteData中的有关Controller数据对象,也就是从请求Url中经过模式匹配出来的{Controller}部分的字符串;

ControllerBase定义了Controller使用到的部分公共属性,好比:用来保存临时数据的TempData,用来返回到View中的Model数据对象ViewBag、ViewData;而且初始化了ControllerContext对象,用来做为后续Controller使用的数据容器和操做上下文;

1 protected virtual void Initialize(RequestContext requestContext) {
2     ControllerContext = new ControllerContext(requestContext, this);
3 } 

在ControllerBase中将对IController.Execute(RequestContext requestContext)方法调用转到了protected abstract void ExecuteCore()方法中;这是一个典型的模板方法模式,下面的继承类Controller,只须要接着protected abstract void ExecuteCore()方法就能和ControllerBase衔接上;

public abstract class Controller : ControllerBase

Controller类继承自ControllerBase,而Controller的任务只须要完成ExecuteCore()方法;

 1 protected override void ExecuteCore() { 
 2 
 3            PossiblyLoadTempData();
 4            try {
 5               string actionName = RouteData.GetRequiredString("action");
 6                if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) {
 7                    HandleUnknownAction(actionName);
 8                }
 9            }
10            finally {
11                PossiblySaveTempData();
12            }
13        } 

Controller.ExecuteCore()的代码将从RouteData中获取执行action的名称,而后经过一个ActionInvoke的组件进行Action的调用,当Action被执行的时候将进入到咱们继承的Controller,如:HomeController:Controller中,在咱们自定的Controller中的方法都将被视为Action的匹配目标之一;

图2:

根据上图的指示,ControllerBase首先是实现IController接口,完成了对Execute(RequestContext requestContext)方法的实现,而后Controller继承ControllerBase类,重写了模板方法ExecuteCore()方法,而后咱们自定义的HomeController实际上是Action的容器,当Controller的ExecuteCore()方法执行时将经过ActionInvoke类进行对HomeController中的方法调用;

4.ASP.NETMVC IController Factory 控制器工厂(Controller的建立)

当清楚了Controller的继承体系以后,下面回到MvcHandler调用的环节;MvcHandler继承自IHttpHandler接口 ,表示它将是ASP.NET真正执行请求处理的地方;在MvcHandler处理请求的方法中ProcessRequest(HttpContextBase httpContext),将经过IControllerFactory接口建立IController接口;

IControllerFactory接口是控制器工厂接口,专门用来实现建立IController对象工厂类,在ASP.NETMVC内部有一个实现了IControllerFactory接口的默认工厂类DefaultControllerFactory,ASP.NETMVC内部是用这个类来建立IController对象的;

1 factory = ControllerBuilder.GetControllerFactory();

获取IDefaultControllerFactory接口须要经过ControllerBuilder对象,ControllerBuilder类是专门用来管理IControllerFactory对象的,同时ControllerBuilder也是应用编程接口,让自定义IControllerFactory对象成为可能;

建立IController须要咱们传入RequestContext对象和ControllerName控制器名称;

1 // Get the controller type
2 string controllerName = RequestContext.RouteData.GetRequiredString("controller"); 
3 factory = ControllerBuilder.GetControllerFactory();
4 controller = factory.CreateController(RequestContext, controllerName);

从RequestContext.RouteData中获取到当前请求的conroller名称,而后用来做为factory.CreateController的参数;

图3:

MvcHandler经过ControllerBuilder对象的静态属性Current获取到ControllerBuilder对象实例,显然ControllerBuilder是一个单例模式的对象;而后经过ControllerBuilder对象获取到DefaultControllerFactory默认IControllerFactory工厂对象,接着利用DefaultControllerFactory建立出IController对象;

 

相关文章
相关标签/搜索