asp.net MVC 应用程序的生命周期(上)

首先我们知道http是一种无状态的请求,他的生命周期就是从客户端浏览器发出请求开始,到得到响应结束。那么MVC应用程序从发出请求到获得响应,都做了些什么呢?

本文我们会详细讨论MVC应用程序一个请求的生命周期,从一个控件到另一个控件是怎样被处理的。我们还会详细介绍一下整个请求的生命周期中,用到的相关组件。因为在平常的开发过程中,我们可能知道怎样去使用MVC框架来处理相关的请求,大部分的时候我们只是在controller和action方法之间做相关的处理,对于真正内在的运行机制可能不是很了解。其实当我们对内在机制有了一定的了解以后,会发现微软的MVC框架的扩展性很强,到处都留有扩展接口,让我们通过扩展能够自己定义自己所需要的处理机制,这也正是为什么MVC框架如此出名的原因。

当我最开始学习使用mvc的时候,困扰我的一个问题就是,一个请求的流程控制是怎样的呢?从view到controller再到action之间经历了什么?那个时候我还不清楚HTTP module和HTTP  handler在处理一个请求中扮演什么样的角色,起什么样的作用呢。毕竟MVC是一个web开发框架,在整个请求处理过程中,肯定包含了http module和http handler。其实还有很多相关的组件包含在一个完整的mvc应用程序请求生命周期里,在整个请求过程中他们都扮演者非常重要的角色。尽管大部分时候我们都使用的是框架提供的默认的函数,但是如果我们了解了每个控件所扮演的角色,我们就可以轻松的扩展和使用我们自己实现的方法,就目前来说MVC是扩展性比较强的框架。

HttpApplication

我们都知道,在ASP.NET MVC框架出现之前,我们大部分开发所使用的框架都

是ASP.NET WebForm.其实不管是MVC还是WebForm,在请求处理机制上,大部分是相同的。这涉及到IIS对请求的处理,涉及的知识较多,我们就不做介绍了,下次有机会我写一篇专文。我们从HttpApplication说起。先看看微软官方是怎么定义HttpApplication的:

定义 ASP.NET 应用程序中的所有应用程序对象共有的方法、属性和事件。此类是用户在 Global.asax 文件中所定义的应用程序的基类。

可能我翻译不是很准确,原文连接在这里:https://msdn.microsoft.com/en-us/library/system.web.httpapplication(v=vs.110).aspx

微软官方文档中Remark里有这么一段话:HttpApplication 类的实例是在 ASP.NET 基础结构中创建的,而不是由用户直接创建的。使用 HttpApplication 类的一个实例来处理其生存期中收到的众多请求。但是,它每次只能处理一个请求。这样,成员变量才可用于存储针对每个请求的数据。

意思就是说ASP.NET应用程序,不管是MVC还是WebForm,最终都会到达一个HttpApplication类的实例。HttpApplication是整个ASP.NET基础架构的核心,负责处理分发给他的请求。HttpApplication处理请求的周期是一个复杂的过程,在整个过程中,不同阶段会触发相映的事件。我们可以注册相应的事件,将处理逻辑注入到HttpApplication处理请求的某个阶段。

在HttpApplication这个类中定义了19个事件来处理到达HttpApplication实例的请求。就是说不管MVC还是WebForm,最终都要经过这19个事件的处理,那么除了刚才说的MVC和WebFrom在请求处理机制上大部分都是相同的,不同之处在哪呢?他们是从哪里开始分道扬镳的呢?我们猜想肯定就在这19个方法中。我们继续往下看。

我们来看看这19个事件:

应用程序按照以下顺序执行由 global.asax 文件中定义的模块或用户代码处理的事件:


事件名称:


简单描述:


BeginRequest


在 ASP.NET 响应请求时作为 HTTP 执行管线链中的第一个事件发生


AuthenticateRequest


当安全模块已建立用户标识时发生。注:AuthenticateRequest事件发出信号表示配置的身份验证机制已对当前请求进行了身份验证。预订 AuthenticateRequest 事件可确保在处理附加的模块或事件处理程序之前对请求进行身份验证


PostAuthenticateRequest


当安全模块已建立用户标识时发生。PostAuthenticateRequest事件在 AuthenticateRequest 事件发生之后引发。预订PostAuthenticateRequest 事件的功能可以访问由PostAuthenticateRequest 处理的任何数据


AuthorizeRequest


当安全模块已验证用户授权时发生。AuthorizeRequest 事件发出信号表示 ASP.NET 已对当前请求进行了授权。预订AuthorizeRequest 事件可确保在处理附加的模块或事件处理程序之前对请求进行身份验证和授权


PostAuthorizeRequest


在当前请求的用户已获授权时发生。PostAuthorizeRequest 事件发出信号表示 ASP.NET 已对当前请求进行了授权。预订PostAuthorizeRequest 事件可确保在处理附加的模块或处理程序之前对请求进行身份验证和授权


ResolveRequestCache


当 ASP.NET 完成授权事件以使缓存模块从缓存中为请求提供服务时发生,从而跳过事件处理程序(例如某个页或 XML Web services)的执行


PostResolveRequestCache


在 ASP.NET 跳过当前事件处理程序的执行并允许缓存模块满足来自缓存的请求时发生。)在 PostResolveRequestCache 事件之后、PostMapRequestHandler 事件之前创建一个事件处理程序(对应于请求 URL 的页


PostMapRequestHandler


在 ASP.NET 已将当前请求映射到相应的事件处理程序时发生。


AcquireRequestState


当 ASP.NET 获取与当前请求关联的当前状态(如会话状态)时发生。


PostAcquireRequestState


在已获得与当前请求关联的请求状态(例如会话状态)时发生。


PreRequestHandlerExecute


恰好在 ASP.NET 开始执行事件处理程序(例如,某页或某个 XML Web services)前发生。


PostRequestHandlerExecute


在 ASP.NET 事件处理程序(例如,某页或某个 XML Web service)执行完毕时发生。


ReleaseRequestState


在 ASP.NET 执行完所有请求事件处理程序后发生。该事件将使状态模块保存当前状态数据。


PostReleaseRequestState


在 ASP.NET 已完成所有请求事件处理程序的执行并且请求状态数据已存储时发生。


UpdateRequestCache


当 ASP.NET 执行完事件处理程序以使缓存模块存储将用于从缓存为后续请求提供服务的响应时发生。


PostUpdateRequestCache


在 ASP.NET 完成缓存模块的更新并存储了用于从缓存中为后续请求提供服务的响应后,发生此事件。


LogRequest


在 ASP.NET 完成缓存模块的更新并存储了用于从缓存中为后续请求提供服务的响应后,发生此事件。

仅在 IIS 7.0 处于集成模式并且 .NET Framework 至少为 3.0 版本的情况下才支持此事件


PostLogRequest


在 ASP.NET 处理完 LogRequest 事件的所有事件处理程序后发生。

仅在 IIS 7.0 处于集成模式并且 .NET Framework 至少为 3.0 版本的情况下才支持此事件。


EndRequest


在 ASP.NET 响应请求时作为 HTTP 执行管线链中的最后一个事件发生。

在调用 CompleteRequest 方法时始终引发 EndRequest 事件。

对于一个ASP.NET应用程序来说,HttpApplication派生与Global.aspx(可以看看我们创建的应用程序都有一个Global.aspx文件),我们可以在Global.aspx文件中对HttpApplication的请求进行定制即注入这19个事件中的某个事件进行逻辑处理操作。在Global.aspx中我们按照"Application_{Event Name}"这样的方法命名进行事件注册。

Event Name就是上面19个事件的名称。比如Application_EndRequest就用于处理Application的EndRequest事件。

HttpModule

ASP.NET拥有一个高度可扩展的引擎,并且能够处理对于不同资源类型的请求。这就是HttpModule。当一个请求转入ASP.net管道时,最终负责处理请求的是与资源相匹配的HttpHandler对象,但是在HttpHandler进行处理之前,ASP.NET先会加载并初始化所有配置的HttpModule对象。

HttpModule初始化的时候,会将一些回调事件注入到HttpApplication相应的事件中。所有的HttpModule都实现了IHttpModule接口,该接口有一个有一个Init方法。

public interface IHttpModule

{    // Methods

void Dispose();    void Init(HttpApplication context);

}

看到Init方法呢接受一个HttpApplication对象,有了这个对象就很容易注册HttpApplication中19个事件中的某个事件了。这样当HttpApplication对象执行到某个事件的时候自然就会出发。

HttpHandler

对于不同的资源类型的请求,ASP.NET会加载不同的HttpHandler来处理。所有的HttpHandler都实现了IhttpHandler接口。

public interface IHttpHandler

{

// Methods

void ProcessRequest(HttpContext context);

// Properties

bool IsReusable { get; }

}

我们看到该接口有一个方法ProcessRequest,顾名思义这个方法就是主要用来处理请求的。所以说每一个请求最终分发到自己相应的HttpHandler来处理该请求。

ASP.NET MVC 运行机制

好了,上面说了那么多,其实都是给这里做铺垫呢。终于到正题了。先看看下面这张图,描述了MVC的主要经历的管道事件:

上图就是一个完整的mvc应用程序的一个http请求到响应的整个儿所经历的流程。从UrlRoutingModule拦截请求到最终ActionResult执行ExecuteResult方法生成响应。

下面我们就来详细讲解一下这些过程都做了些什么。

UrlRoutingModule

MVC应用程序的入口UrlRoutingModule

首先发起一个请求,我们前面讲到ASP.NET 会加载一个HttpModule对象的初始化事件Init,而所有的HttpModule对象都实现了IHttpModule接口。我们看看UrlRoutingModule的实现:

从上图中我们看到UrlRoutingModule实现了接口IHttpModule,当一个请求转入ASP.NET管道时,就会加载 UrlRoutingModule对象的Init()方法。

那么为什么偏偏是UrlRoutingModule被加载初始化了呢?为什么不是别的HttpModule对象呢?带着这个疑问我们继续。

在ASP.NET MVC中,最核心的当属“路由系统”,而路由系统的核心则源于一个强大的System.Web.Routing.dll组件。System.Web.Routing.dll 不是MVC所特有的,但是MVC框架和它是密不可分的。

首先,我们要了解一下UrlRoutingModule是如何起作用的。

(1)IIS网站的配置可以分为两个块:全局 Web.config 和本站 Web.config。Asp.Net Routing属于全局性的,所以它配置在全局Web.Config 中,我们可以在如下路径中找到:“C\Windows\Microsoft.NET\Framework\版本号\Config\Web.config“,我提取部分重要配置大家看一下:

<httpModules>

<add name="OutputCache" type="System.Web.Caching.OutputCacheModule" />

<add name="Session" type="System.Web.SessionState.SessionStateModule" />

<add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" />

<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />

<add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule" />

<add name="RoleManager" type="System.Web.Security.RoleManagerModule" />

<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />

<add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" />

<add name="AnonymousIdentification" type="System.Web.Security.AnonymousIdentificationModule" />

<add name="Profile" type="System.Web.Profile.ProfileModule" />

<add name="ErrorHandlerModule" type="System.Web.Mobile.ErrorHandlerModule, System.Web.Mobile, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

<add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />

<add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

</httpModules>

大家看到没有,我上面标红的那一行:<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />

UrlRoutingModule并不是MVC特有的,这是一个全局配置,就是说所有的ASP.NET请求都会到达这里,所以该Module还不能最终决定是MVC还是WebForm请求。但是也是至关重要的地方。

(2)通过在全局Web.Config中注册 System.Web.Routing.UrlRoutingModule,IIS请求处理管道接到请求后,就会加载 UrlRoutingModule类型的Init()方法。其源码入下:

[TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]

public class UrlRoutingModule : IHttpModule

{

// Fields

private static readonly object _contextKey = new object();

private static readonly object _requestDataKey = new object();

private RouteCollection _routeCollection;

// Methods

protected virtual void Dispose()

{

}

protected virtual void Init(HttpApplication application)

{

if (application.Context.Items[_contextKey] == null)

{

application.Context.Items[_contextKey] = _contextKey;

application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);

}

}

private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)

{

HttpApplication application = (HttpApplication) sender;

HttpContextBase context = new HttpContextWrapper(application.Context);

this.PostResolveRequestCache(context);

}

[Obsolete("This method is obsolete. Override the Init method to use the PostMapRequestHandler event.")]

public virtual void PostMapRequestHandler(HttpContextBase context)

{

}

public virtual void PostResolveRequestCache(HttpContextBase context)

{

RouteData routeData = this.RouteCollection.GetRouteData(context);

if (routeData != null)

{

IRouteHandler routeHandler = routeData.RouteHandler;

if (routeHandler == null)

{

throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0]));

}

if (!(routeHandler is StopRoutingHandler))

{

RequestContext requestContext = new RequestContext(context, routeData);

context.Request.RequestContext = requestContext;

IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);

if (httpHandler == null)

{

throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() }));

}

if (httpHandler is UrlAuthFailureHandler)

{

if (!FormsAuthenticationModule.FormsAuthRequired)

{

throw new HttpException(0x191, SR.GetString("Assess_Denied_Description3"));

}

UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this);

}

else

{

context.RemapHandler(httpHandler);

}

}

}

}

[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]

void IHttpModule.Dispose()

{

this.Dispose();

}

[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]

void IHttpModule.Init(HttpApplication application)

{

this.Init(application);

}

// Properties

public RouteCollection RouteCollection

{

get

{

if (this._routeCollection == null)

{

this._routeCollection = RouteTable.Routes;

}

return this._routeCollection;

}

[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]

set

{

this._routeCollection = value;

}

}

}

时间: 2024-08-11 13:31:18

asp.net MVC 应用程序的生命周期(上)的相关文章

asp.net MVC 应用程序的生命周期

首先我们知道http是一种无状态的请求,他的生命周期就是发出请求开始,到得到响应结束.那么MVC应用程序从发出请求到获得响应,都做了些什么呢? 本文我们会详细讨论MVC应用程序的生命周期和一个请求,从一个控件到另一个控件是怎样被处理的.我们还会详细介绍一下整个请求的生命周期中,用到的相关组件.在平常的开发过程中,我们可能知道怎样去使用MVC框架来处理相关的请求,大部分的时候我们只是在controller和action方法之间做相关的处理. 当我最开始学习使用mvc的时候,困扰我的一个问题就是,一

asp.net MVC 应用程序的生命周期(下)

看看上面的UrlRoutingModule源码里面是怎么实现Init方法的,Init()方法里面我标注红色的地方: application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache); 这一步至关重要哈,看到没有,就是对我们在HttpApplication那19个事件中的PostResolveRequestCache事件的注册. 注册的方法是OnApplication

ASP.NET 应用程序(Application)生命周期概述

原文:ASP.NET 应用程序(Application)生命周期概述 引用MSDN:ASP.NET 应用程序生命周期概述 本 主题概述应用程序生命周期,列出重要的生命周期事件,并描述如何编写适合应用程序生命周期的代码.在 ASP.NET 中,若要对 ASP.NET 应用程序进行初始化并使它处理请求,必须执行一些处理步骤.此外,ASP.NET 只是对浏览器发出的请求进行处理的 Web 服务器结构的一部分.了解应用程序生命周期非常重要,这样才能在适当的生命周期阶段编写代码,达到预期的效果. 应用程序

使用Metrics.NET 构建 ASP.NET MVC 应用程序的性能指标

通常我们需要监测ASP.NET MVC 或 Web API 的应用程序的性能时,通常采用的是自定义性能计数器,性能计数器会引发无休止的运维问题(损坏的计数器.权限问题等).这篇文章向你介绍一个新的替代性能计数器的工具Metrics.NET,因为是它是内部的,所以我们能够向系统中添加更多更有意义的度量标准. Metrics.NET(https://github.com/etishor/Metrics.NET)是一个给CLR 提供度量工具的包,它是移植自Java的metrics,支持的平台 .NET

ASP.NET MVC5请求管道和生命周期

请求处理管道 请求管道是一些用于处理HTTP请求的模块组合,在ASP.NET中,请求管道有两个核心组件:IHttpModule和IHttpHandler.所有的HTTP请求都会进入IHttpHandler,有IHttpHandler进行最终的处理,而IHttpModule通过订阅HttpApplication对象中的事件,可以在IHttpHandler对HTTP请求进行处理之前对请求进行预处理或IHttpHandler对HTTP请求处理之后进行再次处理. 在IIS7之前,如IIS6或IIS5,请

[转载] iOS应用程序的生命周期

iOS应用程序的生命周期 2015-06-23 iOS大全 (点击上方蓝字,快速关注我们) iOS应用程序一般都是由自己编写的代码和系统框架(system frameworks)组成,系统框架提供一些基本infrastructure给所有app来运行,而你提供自己编写的代码来定制app的外观和行为.因此,了解iOS infrastructure和它们如何工作对编写app是很有帮助的. Main函数入口 所有基于C编写的app的入口都是main函数,但iOS应用程序有点不同.不同就是你不需要为iO

[渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:为ASP.NET MVC应用程序使用高级功能

这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第十二篇:为ASP.NET MVC应用程序使用高级功能 原文:Advanced Entity Framework 6 Scenarios for an MVC 5 Web Application 译文版权所有,谢绝全文转载--但您可以在您的网站上添加到该教程的链接. 在之前的教程中,您已经实现了继承.本教程引入了当你在使用实体框架Code

ASP.NET的WEB页面的生命周期

ASP.NET的WEB页面的生命周期,从生成到销毁,也经历了不同的阶段和过程.对于ASP.NET页面生命周期中将执行一些列处理步骤.这些步骤包括初始化.实例化控件.还原和维护状态.运行时间处理程序代码及呈现.一般来说,也要经历如下各个阶段1.页请求:页请求发生在页面生命周期开始之前,用户请求页时,ASP.NET将确定是否需要分析和编译页2.开始:在开始阶段,将设置页属性,如Request和Response.在此阶段,页还将确定请求是回发请求还是新请求,并设置IsPostBack属性3.页初始化:

将最小的OWIN身份验证添加到现有的ASP.NET MVC应用程序

https://weblog.west-wind.com/posts/2015/Apr/29/Adding-minimal-OWIN-Identity-Authentication-to-an-Existing-ASPNET-MVC-Application 将最小的OWIN身份验证添加到现有的ASP.NET MVC应用程序 2015年4月29日•来自毛伊岛,HI•    40条评论 从ASP.NET 4开始,ASP.NET提供了一个相当有用的身份系统.如果您创建一个新项目并选择一个MVC项目并选