Asp.net mvc 框架揭秘之Asp.net +Mvc简介

1、什么是MVC?

介绍MVC之前说一下自治视图(Autonomous View):将UI界面的呈现、交互动作的捕捉响应、逻辑处理流程、数据存储等糅合在一起(如WebForm),我们将这种设计模式成为自治视图

 

自治视图的弊端:

  • 视图和逻辑糅合在一起,不利于逻辑的复用
  • 不利于对UI组件的调试

     

     

MVC是基于关注点分离的方针的架构模式,它将一个人机交互用户的功能分为Model、View、Controller三部分,它们各自具有自己的职责:

 

Model:是对用于状态和业务功能的封装,是同时包含行为和数据的领域模型,Model接收Controller的请求完成相应的业务处理,在状态改变时向View发出通知

 

View:实现可视化界面的呈现,同时捕获用户的交互操作

 

Controller:接收View捕获的交互操作,完成相应的UI逻辑,如果需求涉及业务逻辑的需求,则Controller会直接调用Model来处理,在完成UI逻辑处理后,Controller会控制现有View或创建新的View对用户请求予以响应。

 

 

Model-View-Controller间的交互关系

其中Controller不单单是介于Model和View之间的中介,Model和View之间亦可以直接交互,当Model中的状态发生改变时,它可以直接通知View,View亦可以主动查询Model中的状态信息。

 

MVC与"三层结构"的关系?

两者并没有什么可比性,对于多层架构模式来说,MVC通常是被当做UI层的设计模式(Asp.net mvc通常就被认为是UI层的MVC),而Model更多的表现为业务访问层的入口。

2、IIS与asp.net管道

2.1 IIS 5.x与asp.net

 

 

IIS 5.x 运行在InetInfo.exe 进程中,该进程中寄宿着一个叫做W3SVC(World Wide Web Publishing Serivice)的windows服务,该服务的功能包括Http请求的监听、工作进程和配置管理(通过元数据(Metadata)获取相关配置信息)

 

当收到Http请求后,先根据后缀名判断请求的是否是静态资源,如果是则直接以HTTP返回请求的资源,如果是动态资源,则根据扩展名从IIS的脚本映射找到相应的ISAPI动态链接库(DLL)。

    ISAPI(Internet Server Application Programing Interface)是一组本地的Win 32 API,是Web应用和IIS之间的纽带,ASP.NET ISAPI 对应的DLL为aspnet_isapi.dll(位于sysdir:\Windows\Microsoft.NET\Framework\versionInfo),ISAPI支持ISAPI (ISAPI Extension)扩展和ISAPI 筛选(ISAPI Filter),前者是真正处理HTTP请求的接口,后者则是在处理请求之前进行验证、转发或拒绝请求等。

    如果请求的是基于asp.net类型的资源时,asp.net ISAPI 被加载,aspnet_isapi 会创建asp.net的工作进程(如果该进程尚未启动),对于IIS5.x该进程为asp.net.exe,工作进程初始化的过程中,工作进程的主线程初始化CLR,

对于某个Web请求,CLR创建应用程序域,在应用程序域中http运行时(IsapiRuntime)被加载并创建相应的应用,在IIS5.x中,所有的Web应用都存在于同一工作进程(aspnet_wp.exe)的不同应用程序域中。

 

2.2 IIS 6.x与Asp.net

IIS 5的在处理http请求上的缺陷:

  1. Asp.net ISAPI 动态链接库被直接加载到InetInfo.exe进程中,它和工作进程之间是基于进程之间的通信,易造成性能上的瓶颈
  2. 所有的Web应用运行在同一工作进程的不同应用程序域中,基于应用程序域的隔离不能从根本上解决不同应用程序间的影响

 

为解决如上的第一个问题,IIS6.x将aspnet_isapi动态链接库直接加载到工作进程中,针对第二个问题,IIS 6创建应用程序池的机制,我们可以为一个或多个Web应用创建应用程序池,每一个应用程序池对应一个工作进程,为Web应用提供了基于进程的隔离。

注:图中的HTTP.SYS是一个监听HTTP请求的内核驱动,当HTTP.SYS监听到一个HTTP请求后,将其分发给W3SVC, W3SVC解析出请求的URL,并根据Metadata中的URL与Web应用的映射关系定义请求的Web应用,并进一步得到目标应用运行的工作进程,如果尚未创建则为该请求创建工作进程(称之为请求式创建),在工作进程的初始化过程中aspnet_isapi动态链接库被加载。。。。。,之后Asp.net ISAPI加载CLR,创建应用程序域,初始化应用程序。

 

2.3 IIS 7与 Asp.net

IIS 7 在请求的监听和分发机制上进行了革新性的改进,主要体现在Windows进程激活服务WAS(Windows Process Activation Service)的引进,将IIS6中W3SVC服务承载的部分功能分流给了WAS,W3SVC承载的功能主要有三个部分:

  1. HTTP请求接收:接收HTTP.SYS分发的HTTP请求
  2. 配置管理:从Metadata中加载配置信息配置相关组件
  3. 进程管理:进程的创建、回收、监控进程

IIS 7 将后两个功能分给了WAS,而HTTP请求的接收仍然由W3SVC,WAS的引入为IIS 7提供了对非http协议的支持,WAS通过监听器适配器接口抽象出不同协议监听器(asp.net mvc 4框架解密 p17)

 

不论是从W3SVC接收到的http请求,还是从WCF监听适配器接收到的请求,最终都会提交到WAS来处理,如果相应的工作进程尚未建立,则创建,否则将请求分发给其它的进程进行后续处理,WAS在请求处理过程中,通过相应的配置管理模块加载配置信息,对相关组件进行配置,与IIS5与IIS 6不同的是,IIS7的配置信息并不保存在元数据中,而是保存在xml格式的配置文件中,基本的配置在applicationHost.config中。

 

3、ASP.NET 管道

 

HTTP.SYS 接收到HTTP请求后,如果该请求是对该Web应用的第一次请求时,aspnet_isapi加载CLR,CLR会通过APPDomainFactory为该Web应用创建应用程序域,之后一个叫做IsapiRuntime的运行时被加载,被加载的IsapiHttpRuntime会接收该请求,IsapiHttpRuntime会首先创建一个ISAPIWorkerRequest(HttpWorker类的子类,所有的HTTP请求都必须封装到一个HTTPWorkerRequest对象中才能进行后续处理)的对象,并将该对象传递给Asp.net 的运行时HttpRuntime,此时HTTP请求进入Asp.net 管道,HttpRuntime会根据IsapiWorkerRequest对象创建用于当前请求上下文对象HTTPContext对象

 

当成功创建HttpContext对象后,HttpRuntime会利用HttpApplicationFactory创建新的或获取一个HttpApplication对象,HttpApplicationFactory内部维护着一个HttpApplication对象池,HttpRuntime从池中选取HttpApplication对象来处理Http请求,处理完成后将对象释放会对象池中(每个HttpApplication只能处理一次请求)

    在HttpApplication对象的初始化过程中,会根据配置文件加载并初始化已注册的HttpModule对象,对于HttpApplication来说,在处理Http请求的不同阶段会触发不同的事件,而HttpModule就是将这些事件的操作注入到请求处理的过程中(通过注册相应的HttpApplication事件),HttpApplication具有19个管道事件,分别如下:

 

Asp.Net 的许多功能如身份验证、缓存、授权都是通过HttpModule实现的

有关HttpModule和HttpApplication事件注册:http://www.cnblogs.com/kissdodog/p/3527922.html

    真正的Http请求处理是由HttpHandler。对于不同的资源具有不同的HttpHandl(但都实现了IHttpHandler这个接口,IHttpHandler的ProcessRequest方法请求处理的具体实现),例如Web Form对应的HttpHandler为System.Web.PageUI,asp.net Mvc对应的HttpHandler为mvchandler.

    HttpApplication是整个Web应用处理的核心,当收到第一次请求后,Asp.net 会创建多个HttpApplication对象,并将其放入池中,选择一个来处理当前请求,处理完成后不是直接回收,而是释放到HttpApplication对象池中,供后续请求使用,如果池中的所有HttpApplication对象都处于繁忙状态,则创建新的HttpApplication对象。

    针对HttpApplication管道事件的HttpHandler注册有两种方式,一是通过Web.config 配置文件实现,二是通过Global.asmx文件来实现

方法一:

  1. 首先定义一个类实现IHttpModule接口,IHttpModule接口的定义如下:

system.web配置元素的子元素httpModules用来配置网站所使用的HttpModule;httpModules的子元素add用来增加一个新的HttpModule;clear将清除前面注册的所有HttpModule。

  add元素有两个必选的属性name和type,简介如下:

  • name表示这个HttpModule在程序中的名字,在网站应用程序中,可以通过这个名字来找到HttpModule对象的引用。HttpApplication的Modules属性表示这个对象所关联的所有HttpModule对象,通过这个name作为索引器,可以找到对应的HttpModule对象。
  • type表示HttpModule对象的类型名,Asp.net网站可以使用这个类型名,通过反射来动态创建HttpModule对象。类型的写法就是反射中要求的类型名称写法,如果这个类定义在网站中,那么,就是一个包含命名空间的类的全名,否则,在全名的后面,使用逗号(,)分隔,还需要跟上类型所在的程序集的名称,这个程序集的名称不需要包含.dll扩展名。

 

方法二:通过Global.asmx 文件来实现

    在global.asax中,针对HttpApplication的事件处理,可以通过定义特殊命名的方法来实现。首先,这些方法必须符合System.EventHandler,因为所有的HttpApplication管道事件都使用这个委托定义。第二,方法的作用域必须是public。第三,方法的命名格式必须如下:Application_注册的事件名称。按照这种命名方法定义在global.asax中的方法将被自动注册到对应的事件中。

    例如,希望在global.asax中注册PostAuthenticateRequest事件处理,那么在global.asax中应该定义一个如下的方法:

    

 

4、Asp.Net MVC 整体处理流程

    4.1 URL解析

    针对Asp.net mvcWeb应用来说,对Http的请求处理是通过Controller相应的Action方法来实现的,因此Asp.net mvc 的首要任务就是从请求URL中解析出相应的Controller和Action,在Asp.net mvc中URL的解析是通过UrlRoutingModule来实现的。UrlRoutingModule实现了IHttpModule接口,在其的Init()方法中,注册HttpApplication管道事件的第7个事件PostResolveRequtestCache

如下为PostResolveRequestCache 的主要处理代码:

在此期间主要做了几件事:

  1. 将封装有当前请求信息HttpContext对象进一步封装为HttpContextWraper(为HttpContextBase的子类)对象,并将其作为参数传入PostResolveRequestCache方法中
  2. 调用RouteCollection(内部具有一个保存有当前已注册的路由信息的Dictionary集合)的GetRouteData(),如果匹配成功,就返回一个封装有匹配到的Route对象的RouteData对象,否则,就返回null,
  3. 将获取到的RouteData和HttpContext进一步封装为RequestContext对象
  4. 将上步封装好的RequestContext对象作为参数调用RouteDatad的GetRouteHandler属性获取一个IRouteHandler类型的对象(MvcRouteHander)
  5. 调用IRouteHandler的GetHttpHander方法,返回一个IHttpHander类型的对象(mvcHandler)

4.2 Controller的激活

    UrlRoutingModule通过路由表解析当前的Http请求后得到一个用于封装路由数据的RouteData,之后调用RouteHandler的GetHttpHandler方法得到HttpHandler对象并注册到Http上下文中,由于RouteData的RouteHandler来自Route的RouteHander,默认情况下是一个mvcrouteHander,所以默认情况下用于处理mvc请求的就是这个mvchandler(可以查看RouteCollectionExtension的maproute方法来确认),Controller对象的激活和执行就是在mvcHandler中进行的。

    MvcHandler 实现了IHttpHandler接口,在其ProcessRequest方法中实现了Controller的激活和执行

 

PR方法中的代码如下:

主要功能的实现在封装的内部函数ProcessRequestInit()中,方法如下

其中主要做了如下几件事:

  1. 从参数中获取当前请求的Http上下文(参数中传入的是一个HttpContextWraper)
  2. 从RequestContext(封装的RouteData和HttpContext)中获取Controller名称
  3. 通过ControllerBuilder(用来设置或获取Controller对象工厂)对象中获取创建Controller的工厂对象(默认为DefaultControllerFactory对象)
  4. 调用工厂对象的CreateController方法根据RequestContext和控制器名称创建Controller对象(通过反射)

 

4.3 Action的执行

Action的执行是在Controller的Excute(RequestContext context)方法中执行的(Controller的Excute()方法是在mvcHandler的ProcessRequest()方法中执行的(见PR方法截图)),其核心在于对应Action方法的执行和作为方法返回的ActionResult的执行

注意:ControllerBase和Controller都实现了IController接口,而Controller又继承自ControllerBase,在ControllerBase中显式实现了接口IController

在IController的Excute方法中调用的同名的实例方法Excute(RequestContext requestContext),

 

可以看出,实例方法Excute的主要操作有调用了ControllerBase的ExcuteCore()方法,而该方法是一个虚方法,所以任何继承ControllerBase的类都必须重写该方法,在Controller方法中并没有显式实现IController的Excute(可能说的有歧义,这里指在Controller继承了ControllerBase的Excute方法,并没有自己实现),而是重写ExcuteCore方法,重写的Excute方法如下:

首先调用GetActionName方法获取请求的action名称,其后调用ActionIInvoker的InvokeAction方法,这个方法主要做了如下的几件事:

  1. 执行Action过滤器方法
  2. 执行Action方法
  3. 执行作为方法返回的ActionResult

如果这个ActionResult是ViewResult的话,就调用相应的视图引擎渲染视图

   以上就是Asp.net mvc 的一次整体请求处理流程。

posted @ 2016-06-11 09:41  空城守望城空  阅读(782)  评论(0编辑  收藏  举报