admin 管理员组

文章数量: 887173


2024年1月13日发(作者:时间戳格式化为时间)

MVC那些不为人知的一些事情

有好些理解是直接写在源码里的,然后通过截图,放到这个Word里面,所以图很重要,有图有证据嘛。有些不清晰的,就放大来看啦(Ctrl+滚轮上)哈哈···

MVC运行的整体机制整体路线:

浏览器发送请求

IIS捕获到请求,根据请求里面的信息找到对应的程序集

加载程序集,创建运行环境

包装请求信息(wr)

调用HttpRuntime的PR方法创建application(读取global文件,调用Application_Start方法)

初始化(读取配置文件(用户+系统的),调用InitModlues()方法),第七个事件里注册了UrlRoutingModules方法

创建MvcHandler,它包含了请求上下文信息,路由信息,并将其添加到上下文HttpContext

调用MvcHandler的PR方法,创建控制器,调用action(用户在Controller下面写的方法),将用户数据保存到父类里面。

执行action返回ViewResult(包含了用户执行后的数据)

拿取视图引擎,调用Render()方法,生成Html代码,创建视图。

能力有限,没求甚解。愿互相学习,互相指正,共同进步。

【你必须非常努力,才能看起来毫不费力!】

和的区别从UrlRoutingModules这个方法说起。

.NET 程序运行的时候,会先执行初始化,也就是调用Global文件里的Application_Start方法。

通过反射创建这个文件里的类(在里面就是Global类,在MVC下是MVCApplication类,它们继承自HttpApplication类。) 如果Global文件不存在,就直接创建他们的父类:HttpApplication。

接着在确保调用了Application_Start方法后,创建ApplicationInstance实例(对象池),然后进行初始化。

在.NETFrameWork 4.0,初始化时读取配置文件(包括系统配置文件和用户自定义的配置文件)。

在系统配置文件下有一个HttpModules。内容如下:

读取HttpModules节点,为其创建对应的对象,循环调用里面的Init方法,在这个方法里,向application里面的事件注册方法(用户的代码)。完成AOP编程。

1

MVC 在配置文件里,写了一个UrlRoutingModule,创建这个方法,在这个方法里的Init方法里,向管道事件的第七个事件注册了一个方法。这个方法主要做的是将MVCHandler添加到上下文中(HttpContext).【下面这个图是从浏览器请求开始的】

那么要研究MVC就从这个UrlRoutingModule(继承IHttpModule接口)方法开始研究。

2

UrlRoutingModule类下的Init()方法在第七个事件下注册了一个方法:

这个方法里:

1、 拿到HttpApplication对象,

2、 将上下文对象HttpContext封装到HttpContextBase里面。

3、 传入上下文对象,执行事件。

---------------------------------------------------------分割线------------------------------------------------------

3

1、 拿取路由数据。

4

1.1根据上下文,进行过滤,判断请求的是不是一个已经存在的文件,如果是,则直接返回这个文件。

1.2如果请求的不是存在的文件,那么获取路由数据。

获取路由数据的时候,调用的是RouteBase类下面的GetRouteData(httpContext)方法。

1.2.1RouteBase下的GetRouteData方法,但是,实现这个方法的类是Route。

继续看GetRouteData()方法:

因为在Reflector下不能写注释,我转到了MVC源码下面。

到这里,是时候说明一下那个RouteHandler是哪里来的了。

其实它就是MVCRouteHandler。我们到Global文件下去看。

5

A:这里注册路由,调用MvcApplication下的RegisterRoutes方法。即B

B:将路由信息传入到MapRoute下面,它其实就是返回一个Route对象回来。具体做了什么呢?

上面我在1.2.2那里标记了一下,那个就是Route类的一个构造函数

Route(string url,IRouteHandlerrouteHandler),

然后在这里new了一个Route对象,并传入了一个url和一个MvcRouteHandler对象,因此,到这里,可以知道routeHandler就是MvcRouteHandler。而上面已经确定了,this就是Route,那么Route下的RouteHandler也就是MvcRouteHandler。参看1.2.3!在1.2.2里将routeHandler传给1.2.3的RouteHandler。

我们接着说GetRouteData()方法。

简单地说,GetRouteData就是拿取路由数据,将MvcRouteHandler添加到RouteData对象里

RouteData data=new RouteData(this,andler).但是在里面做了一些检查,检查路径,检查约束。最后返回这个data。

还是看一下RouteData里面的内容吧:

6

这里面包含了MvcRouteHandler(RouteHandler),命名空间(dataTokens),路由数据?没去研究RouteValueDictionary()。反正这里包含了我们传进来的路由信息。保存在RouteCollection集合里面。提一下:RouteTable里也一个RouteCollection,静态的,是为了能够在整个生命周期里面使用到路由数据。如下图:

接着我们继续看第二部分吧。

2、 在第一部分里,已经将MvcRouteHandler添加到了routeData里面,返回一个data对象。而MvcRouteHandler最后传递为RouteHandler。

第二部分:IRouteHandlerrouteHandler = andler;从routeData里面获取到routeHandler对象。为什么是IRouteHandler类型呢?擦,因为从Route构造函数开始就是IRouteHandler类型定义来接收的····

接着看第三部分

3、 RequestContextrequestContext = new RequestContext(context, routeData);

tContext = requestContext;

将context对象和上面拿到的路由数据routeData封装到RequestContext里面,然后赋值给HttpContextBase下的HttpRequestBase的requestContext属性。也就是将路由数据和封装过的上下文信息再添加到上下文里面。

IHttpHandlerhttpHandler = pHandler(requestContext);

GetHttpHandler(requestContext) 这里返回一个MvcHandler。

7

然后我们去MvcHandler下去看看,还是不看先,留到后面看吧。应该就是调用PR方法执行后面一系列流程了。留待后面揭秘。暂时知道GetHttpHandler方法里返回这个MvcHandler对象就行了。接收类型是IhttpHandler接口!!!!!!!!!熟悉啦~~

接着看第四部分,也是在第七个事件里注册的方法执行的最后一步。

andler(httpHandler);

这个方法是把获得的那个MvcHandler添加到上下文对象中。这个方法具体做啥先。

先得说一下,在第三部分的时候,已经将context传进了HttpContextBase里。

待会用到HttpContextWrapper,它继承HttpContextBase,重写了HttpContextBase里面的ReMapHandler方法。。。。详细见图:

好了,进入ReMapHandler方法:

Typetype = e();//获得类型:MvcHandler

handlerType = lyQualifiedName;//获得当前类型在程序集里面的名字:dler

handlerName = me;//获得全名

this._remapHandler = handler;//将MvcHandler添加到上下文对象中,这里的this就是HttpContext

在第七个事件里注册的方法,最终就是拿到路由数据,将创建的Handler添加到上下文中。

PostResolveRequestCache(HttpContextBase context)到此,运行完···接着深入。

8

在原来的 的整个运行周期上,挑中合适的时机,弄出分叉来,然后诞生了。

那么这个时机在哪里呢?

1、 FrameWork 4.0下会先读取系统配置文件,这个文件下的节点HttpModules里配置了一个UrlRoutingModule,在读取这个配置文件的时候,就会创建这个Module对象,创建方法,在初始化的时候在第七个事件PostResolveRequestCache里注册方法,这个方法里面封装上下文和路由信息,创建了MvcHandler并添加到上了下文里(HttpContex)。

2、 在第八个事件(PostMapRequestHandler)执行时(是不是在执行的时候检查呢?还是在执行之前检查?这个还没有考证!),会先判断上面的那个_remapHandler是不是空的,如果不空(MVC执行程序),就不再创建页面类对象,直接返回Handler。否则根据请求路径创建页面类对象······等执行运行机制。

以上两个时机造就了MVC。在创建的MvcHandler里有我们最常见的PR(ProcessRequest)方法.

现在开始揭秘MvcHandler到底干了什么。(只研究主要的)

在整个运行的管道第九个事件里要拿到请求的Session,会检查当前请求的类是否实现了IRequiresSessionState接口。再看MvcHandler类,

它已经实现了这个接口!其实,这个MvcHandler就相当于是一个页面类对象。可以自己去该类下面看看。

跟一样,在第十一和十二个事件之间会调用页面类对象的PR方法,里调用page(继承自IHttpHandler)类的PR(是实现IHttpHandler的)方法。在里则调用MvcHandler(也继承自IHttpHandler)里的PR(也是实现IHttpHandler的)方法。

9

老样子,进入PR方法:

1、创建一个控制器接口对象,在初始化的时候为其赋值。创建控制器!根据拿到的控制器的类型,创建的行为是由工厂完成的!工厂在这里起到的作用除了提供多态外,还提供一个对象池,每一次创建控制器的时候都会到这个池里面去检查。

在ProcessRequestInit()方法里面:

接着走下去,看CreateController()方法。不做太多的解释了,到Create()方法,再到Activitor下的CreateInstance方法。反正最终就是根据type创建出这个实例。见下面两个图:

10

2、执行Execute()方法,这是一个很关键的方法。

11

在Initialize方法里:(this就是ControllerBase)

主要看ExecuteCore()方法:

好啦,走到这里终于到了调用Action了。在Action里面会存在一些与视图相关的东西。因此在action里面要创建视图(View()方法),设置数据,返回ViewResult···

从读取配置文件

在第七个事件里注册方法,创建MvcHandler,将路由信息和请求上下文信息传进去

MvcHandler为类页面类对象,调用里面的PR方法,通过反射创建controller对象,调用里面的Action。

Action就是我们平时直接写代码的方法。返回一个ActionResult return View();

So

接下来研究Action,是怎么创建视图返回的,又是怎样设置保存后台数据等等···

12

1、 执行程序员的action方法,返回ActionResult:

ViewResult就是。

这些数据保存到HomeController的父类的父类ControllerBase里面,然后再在Controller类里面new了一个ViewResult,执行action的时候就返回这个ViewResult,将这些数据传递保存到ViewResultBase里面,以供创建视图的时候使用!

2、 拿到ViewResult并保存到AuthContext里面(),开始执行ExecuteResult()方法!

13

1、 FindView(context):

1.1

1.1.1

1.1.1.1

14

找RazorViewEngine:

最终找到了FindView啦····

在FindView返回关联本地视图的引擎(啥?不懂),有母版页的时候的!

或者创建一个新的视图引擎····CreateView()

在RazorViewEngine下面找到了CreateView()

So

拿到了视图引擎了,Public IView View{set;get;} 已经赋值,

那么在Render()方法里面生成Html代码,并放入Response里····哈,整一条路线终于清晰啦。MVC整个机制就到这里·····

15


本文标签: 方法 创建 对象 请求 调用