Refer: ASP.NET Application Life Cycle Overview
在ASP.NET每次初始化并且处理请求的过程中,有几个步骤是必须会执行的。ASP.NET组件只是处理浏览器客户端发送的服务请求的服务端架构的一部分。了解ASP.NET应用程序的生命周期,我们可以在相对应的步骤中插入我们自己的代码,来实现一些自定义的功能。
一个ASP.NET程序的生命周期通常情况下要经历下述步骤:
1.用户从客户端(浏览器)向服务器发送一个请求
一个ASP.NET程序的生命周期开始于客户端(通常是浏览器)向服务器(通常是IIS)发送一个请求。ASP.NET是IIS的一个ISAPI扩展,IIS的元数据库里保存了文件扩展名与ISAPI的映射。当IIS接收到一个请求时,会检查所请求的文件的扩展名,如果这个扩展名映射到了ISAPI,那么IIS就会将该请求交给ASP.NET去处理。例如ASP.NET会处理扩展名为.aspx, .ascx, .ashx, asmx的文件,因为这些扩展名都映射到了ISAPI。
2.ASP.NET程序第一次接收到客户端的请求
当一个ASP.NET程序第一次接收到请求时, ApplicationManager 类会创建一个应用程序域,应用程序域可以让应用程序与全局资源隔离开,以便于应用程序可以独立的卸载。在这个应用程序域里面,会构造一个 HostingEnvironment 类的实例,这个实例包含了所访问的程序的相关信息,比如ID、所在的虚拟目录等。
3.针对每次请求,一些ASP.NET核心对象被构造
在应用程序域创建完,并且HostingEnvironment 对象被初始化之后,ASP.NET会构造一些核心对象,例如 HttpContext,HttpRequest, 和HttpResponse。
HttpContext 类里面包含了HttpRequest 对象和HttpResponse 对象。
HttpRequest 对象包含了当前请求的一些信息,比如cookies和浏览器的信息。
HttpResponse 对象包含了向客户端的响应信息,比如cookies和所有的render。
4.构造一个HttpApplication对象,分配给当前请求
在所有的核心对象都被初始化之后,会构造一个HttpApplication 类对象,然后当前的程序便开始启动。
如果程序包含一个 Global.asax文件,那么ASP.NET会构造一个继承自HttpApplication类的Global.asax类对象,然后用这个对象来表示当前的程序。
当第一次访问一个ASP.NET程序的页面或者进程时,一个新的HttpApplication实例会被构造。然而,为了最大化的提升性能,一个HttpApplication 实例可能会在后来的多次请求中被重用。
在HttpApplication 实例被构造之后,程序中配置的所有module会被创建,然后HttpApplication 的 Init 方法被调用。
5.用第4步创建好的HttpApplication管道来处理请求
在处理请求的过程中,HttpApplication 会执行以下事件,感兴趣的开发人员可以扩展以下事件。
1.验证请求,检查浏览器发送的信息,并且确定该信息是否包含潜在的恶意标签。详情参考 ValidateRequest 和 Script Exploits Overview.
2.如果在Web.config文件的UrlMappingsSection节点下,有配置URL映射的话,则执行URL映射
3.调用BeginRequest事件
4.调用AuthenticateRequest事件
5.调用PostAuthenticateRequest事件
6.调用AuthorizeRequest事件
7.调用PostAuthorizeRequest事件
8.调用ResolveRequestCache事件
9.调用PostResolveRequestCache事件
10.根据请求的文件的扩展名,和在应用程序的config文件(Web.config)里面配置的映射,来选择一个相应的HttpHandler(HttpHandler实现了 IHttpHandler 接口)来处理请求。如果请求的文件是一个页面,该页面继承自Page类,那么ASP.NET会先编译这个页面,然后构造这个页面的实例。
11.调用PostMapRequestHandler事件
12.调用AcquireRequestState事件
13.调用PostAcquireRequestState事件
14.调用PreRequestHandlerExecute事件
15.调用相应HttpHandler的ProcessRequest方法(或者BeginProcessRequest方法)
16.调用 PostRequestHandlerExecute事件
17.调用ReleaseRequestState事件
18.调用PostReleaseRequestState事件
19.如果定义了 Filter 属性,则执行 response 筛选
20.调用UpdateRequestCache事件
21.调用PostUpdateRequestCache 事件
22.调用EndRequest事件
生命周期的事件和 Global.asax
在ASP.NET程序的生命周期的执行过程中,调用了一系列的事件和方法,而且我们可以重写其中一部分。我们可以在我们的web application 的根目录下,创建一个Global.asax文件,在该文件中来处理一些事件和方法。
如果创建了一个Global.asax文件,ASP.NET会把它编译成一个类(该类继承自HttpApplication),然后ASP.NET会用这个类来表示程序。
Global.asax会定义一些名字以Application_开头的事件,例如Application_BeginRequest,ASP.NET会自动绑定这些事件。
但是 Application_Start 和 Application_End 这两个事件比较特殊,它们不是HttpApplication 实例的事件,而是ASP.NET在应用程序域的生命周期中调用它们。
一些常用的生命周期事件和方法:
Application_Start
在一个ASP.NET程序第一次被请求(比如第一次访问页面)的时候调用该方法。这个方法在整个生命周期中只被调用一次。我们可以用这个方法来执行一些启动任务,比如把数据加载到缓存中,或者初始化静态字段。在程序启动阶段,只可以初始化静态字段,尽量不要初始化实例字段,因为实例字段只应用于第一个HttpApplication的实例
Application_event
上述生命周期第5阶段中列出的一系列事件,这些事件在生命周期中合适的时间被调用。
HttpApplication.Init
该方法在每次模块被创建完,然后构造HttpApplication实例后被调用。
该方法在程序被销毁之前被调用,我们也可以手动调用Dispose,来释放非托管资源。
Application_End
该方法仅在程序被卸载的时候调用,整个生命周期中只被调用一次。