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

简介:

阅读目录:

  • 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:

140954800.jpg

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

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

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

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

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

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

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

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

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

1
public  abstract  class  Controller : ControllerBase

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

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

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

图2:

141200927.jpg

根据上图的指示,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
2
3
4
// Get the controller type
string  controllerName = RequestContext.RouteData.GetRequiredString( "controller" );
factory = ControllerBuilder.GetControllerFactory();
controller = factory.CreateController(RequestContext, controllerName);

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

图3:

141319320.jpg

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






 本文转自 王清培 51CTO博客,原文链接:http://blog.51cto.com/wangqingpei557/1315881,如需转载请自行联系原作者
相关文章
|
2月前
|
设计模式 Java 应用服务中间件
Tomcat 架构原理解析到设计借鉴
Tomcat 架构原理解析到设计借鉴
120 0
|
2月前
|
设计模式 Java 应用服务中间件
Tomcat 架构原理解析到架构设计借鉴
Tomcat 架构原理解析到架构设计借鉴
78 0
|
2月前
|
资源调度 算法 JavaScript
Python基础专题 - 超级详细的 Random(随机)原理解析与编程实践
Python基础专题 - 超级详细的 Random(随机)原理解析与编程实践
51 0
|
25天前
|
存储 数据采集 监控
SkyWalking全景解析:从原理到实现的分布式追踪之旅
SkyWalking全景解析:从原理到实现的分布式追踪之旅
66 1
|
1天前
|
架构师 安全 Java
资深架构师带你解析Synchronize关键字原理
众所周知 Synchronize 关键字是解决并发问题常用解决方案,有以下三种使用方式:
7 0
|
1天前
|
Java 关系型数据库 数据库连接
Spring源码解析--深入Spring事务原理
本文将带领大家领略Spring事务的风采,Spring事务是我们在日常开发中经常会遇到的,也是各种大小面试中的高频题,希望通过本文,能让大家对Spring事务有个深入的了解,无论开发还是面试,都不会让Spring事务成为拦路虎。
11 1
|
5天前
|
存储 安全 Java
Go Slice的底层实现原理深度解析
在Go语言的世界里,切片(Slice)是一种极其重要的数据结构,它以其灵活性和高效性在众多编程场景中扮演着核心角色。本文将深入探讨Go切片的底层实现原理,通过实例和源码分析,带你领略Go语言设计之美。
|
7天前
|
设计模式 存储 前端开发
Java Web开发中MVC设计模式的实现与解析
Java Web开发中MVC设计模式的实现与解析
|
7天前
|
缓存 前端开发 JavaScript
前端性能优化实践与原理解析
【2月更文挑战第3天】 在当今互联网时代,前端性能优化已经成为了开发人员必须要面对的重要课题。本文将结合实际案例,探讨前端性能优化的一些实践方法,并深入分析其背后的原理,旨在帮助开发者更好地理解和应用前端性能优化技术。
11 5
|
9天前
|
测试技术 开发者 Python
Python中的装饰器(Decorators)原理与应用解析
在Python编程中,装饰器(Decorators)是一种强大的工具,能够灵活地扩展函数或类的功能,提高代码的可复用性和可维护性。本文将深入探讨装饰器的原理、使用方法以及常见应用场景,帮助读者更好地理解和运用这一重要的Python特性。

相关产品

  • 云迁移中心
  • 推荐镜像

    更多