ASP.NET请求处理全过程

一个ASP.NET请求过程中,从浏览器中发出一个Web请求 到 这个请求被响应并显示在浏览器中的过程中究竟会发生哪些不同的事件,当我们进入这个事件之旅时,我们也会试着明白在请求处理的每个事件当中我们可以做什么业务逻辑处理操作。

首先把整个过程大致分成两步:

  • ASP.NET会创建一个能够处理请求的环境。换句话说,它会创建一个包含请求、响应以及上下文对象的应用程序对象来处理这个请求。
  • 一旦ASP.NET环境被创建,用户请求就会通过由modules(管道)、handlers(处理程序)和page objects(页面对象)触发的一系列事件进行处理。简而言之,我们暂且将此步称为MHPM(Module、Handler、Page和Module Event)。

ASP.NET环境的创建

  • 第一步:用户请求到达IIS后,发现处理不了这个后缀的文件,就去查找映射表。IIS首先会检查哪一个ISAPI扩展能够处理这个请求,这会取决于文件的后缀名。例如:如果请求的是一个'.aspx'的页面,那么就会被传递到'aspnet_isapi.dll'来进行处理。
  • 第二步:如果这是该网站的首次请求,那么一个称为'ApplicationManager'的类会首先创建一个该网站可以运行的应用程序域(App Domain)。正如我们所知,应用程序域隔离部署在同一台IIS服务器上的两个不同的Web应用程序。因此,即使其中一个应用程序域出现了错误,也不会影响其他应用程序域的正常运作。
    应用程序域

    .NET平台下,程序集并没有直接加载进 进程 中(传统的Win32程序是直接承载的)。.NET可执行程序承载在进程的一个逻辑分区中,术语称应用程序域(简称AppDomain)。应用程序域是.NET引入的一个新概念,它比进程所占用的资源要少,可以被看作是一个 轻量级的进程。

  • 第三步:在新创建的应用程序域中,会创建ASP.NET的宿主环境,也就是HttpRuntime对象。一旦宿主环境被创建完成,网站调用HttpRuntime类的静态方法处理请求,ASP.NET最核心的对象如HttpContextHttpRequestHttpResponse对象都会被创建好。HttpApplication对象将会被分配给一系列的ASP.NET核心对象来处理请求的页面。

    这里面主要包括:

    • 分析请求报文,并将报文数据封装到一个叫HttpWorkRequest类对象应用的属性中
    • 通过调用HttpApplicationFactory类的一个静态方法创建HttpApplication对象(这里每次HttpApplicationFactory都会到HttpApplication池中去查找,看看有没用空闲的HttpApplication对象,如果有,就直接拿来使用,否则才创建新的使用,网站针对此次请求的所有运行过程都在这个对象中完成)

      如果你的系统中存在一个global.asax文件,那么这个global.asax文件的对象也会被创建。但是,需要注意的是你的global.asax需要继承自HttpApplication类。

      global.asax

      Global.asax 文件(也称作 ASP.NET 应用程序文件)是可选文件,包含用于响应 ASP.NET 或 HttpModule 引发的应用程序级别事件的代码。(换句话说,我们可以自定义后面我们所要介绍的一些事件,因为请求处理流程会经历后面的10多个事件,我们可以写代码来自定义其中的一些事件,加一些我们想做的业务逻辑操作,比如:URL重写、身份验证、图片水印等等。)

    • 创建HttpContext对象,这个对象是当前请求的上下文环境,里面包含处理请求的所有参数数据,其中最重要的就是HttpRequest和HttpResponse对象。

      HttpRequest

      对象主要包含了所有的请求信息,这些信息来源于HttpWorkRequest对象中包含的属性:Form(客户端表单数据)、QueryString(客户端url参数)

      HttpResponse

      主要包含了TestWriter对象,用来保存页面类型执行过程中要输入给浏览器的数据

    • 因为HttpApplication里面运行IHttpHandler handler=(通过反射方式创建的被请求页面类对象) 被请求页面对象里的ProcessRequest方法,所以,需要将HttpContext对象传入到HttpApplication中来,即HttpApplication对象将会被分配给一系列的ASP.NET核心对象来处理请求的页面
  • 第四步:一旦所有核心的ASP.NET对象被创建好,HttpApplication对象就会随之被创建来服务这个请求。如果你的系统中存在一个global.asax文件,那么这个global.asax文件的对象也会被创建。但是,需要注意的是你的global.asax需要继承自HttpApplication类。

    global.asax

    Global.asax 文件(也称作 ASP.NET 应用程序文件)是可选文件,包含用于响应 ASP.NET 或 HttpModule 引发的应用程序级别事件的代码。(换句话说,我们可以自定义后面我们所要介绍的一些事件,因为请求处理流程会经历后面的10多个事件,我们可以写代码来自定义其中的一些事件,加一些我们想做的业务逻辑操作,比如:URL重写、身份验证、图片水印等等。)

  • 第五步:此时HttpApplication对象将会被分配给一系列的ASP.NET核心对象来处理请求的页面。
  • -->

  • 第四步:这时,HttpApplication开始通过HTTP管道事件、处理程序(Handlers)和页面事件来处理请求了。也就是说:它会触发 MHPM 中的事件来处理请求。

下图则形象地展示了在一个ASP.NET请求过程中的重要内部对象模型。最高层是ASP.NET运行时,它创建了一个应用程序域(AppDoamin),下层则创建了一个包含request、response以及context对象的HttpRuntime。

.NET平台处理HTTP请求的过程大致如下:

  • 1、IIS得到一个请求;
  • 2、查询脚本映射扩展,然后把请求映射到aspnet_isapi.dll文件
  • 3、代码进入工作者进程(IIS5里是aspnet_wp.exe;IIS6里是w3wp.exe),工作者进程也叫辅助进程;
  • 4、.NET运行时被加载;
  • 5、非托管代码调用IsapiRuntime.ProcessRequest()方法;
  • 6、每一个请求调用一个IsapiWorkerRequest;
  • 7、使用WorkerRequest调用HttpRuntime.ProcessRequest()方法;
  • 8、通过传递进来的WorkerRequest创建一个HttpContext对象
  • 9、通过把上下文对象作为参数传递给HttpApplication.GetApplicationInstance(),然后调用该方法,从应用程序池中获取一个HttpApplication实例;
  • 10、调用HttpApplication.Init(),启动管道事件序列,钩住模块和处理器;
  • 11、调用HttpApplicaton.ProcessRequest,开始处理请求;
  • 12、触发管道事件;
  • 13、调用HTTP处理器和ProcessRequest方法;
  • 14、把返回的数据输出到管道,触发处理请求后的事件。
  • 当客户端向Web服务器请求一个页面文件时,这个HTTP请求会被inetinfo.exe进程截获(WWW服务),它判断文件后缀,如果是*.aspx、*.asmx等,就把这个请求转交给aspnet_isapi.dll,而aspnet_isapi.dll则会通过一个Http PipeLine的管道,将这个HTTP请求发送给w3wq.exe进程,当这个HTTP请求进入w3wq.exe进程之后,Asp.Net framework就会通过HttpRuntime来处理这个HTTP请求,处理完毕后将结果返回给客户端。当一个HTTP请求被送入到HttpRuntime之后,这个HTTP请求通过HTTP管道(HttpRuntime是HTTP管道的入口)被送入到一个被称之为HttpApplication Factory的一个容器当中,而这个容器会给出一个HttpApplication实例来处理传递进来的HTTP请求,同时HttpApplication实例会创建一个HttpContext对象来记录HTTP请求的上下文,而后这个HTTP请求会依次进入到如下几个容器中:HttpModule --> HttpHandler Factory --> HttpHandler.当系统内部的HttpHandler的ProcessRequest方法处理完毕之后,整个Http Request就被处理完成了.如果想在中途截获一个HttpRequest并做些自己的处理,就应该在HttpRuntime运行时内部来做到这一点,确切的说时在HttpModule这个容器中做到这个的。

通过MHPM触发的事件处理请求

一旦HttpApplication创建好,它就开始处理请求了。它经历了三个不同的部分:HttpModulePageHttpHandler。当它经过这些部分时,它将调用不同的事件,而这些事件的逻辑处理还可以由开发者来进行扩展和增加自定义处理。

先来了解一下什么是HttpModule和HttpHandlers。他们帮助我们在ASP.NET页面处理过程的前后注入自定义的逻辑处理

他们之间主要的差别

如果你想要注入的逻辑是基于像'.aspx','.html'这样的扩展名,那么你可以使用HttpHandler。换句话说,HttpHandler是一个基于处理器的扩展。

如果你想要在ASP.NET管道事件中注入逻辑,那么你可以使用HttpModule。也可以说,HttpModule是一个基于处理器的事件。

下面是请求处理过程的逻辑流程,其中有4个重要的步骤
  • 第一步(M:HttpModule):客户端请求开始被处理。在ASP.NET引擎执行和创建HttpModule触发事件(在此过程中,你也可以注入自定义逻辑)之前,有6个事件你可以在页面对象创建之前来使用,它们分别是:BeginRequestAuthenticateRequestAuthorizeRequestResolveRequestCacheAcquireRequestState 以及 PreRequestHandlerExecute
  • 第二步(H:HttpHandler):一旦以上6个事件被触发后,ASP.NET引擎就将会调用 ProcessRequest 事件,即使你已经在项目中实现了HttpHandler。
  • 第三步(P:ASP.NET Page):一旦HttpHandler逻辑执行,ASP.NET页面对象就被创建了。而ASP.NET页面被创建,一系列的事件也会随之被触发,它们可以帮助我们自定义逻辑注入到这些事件里边。在此过程中,有6个重要事件给我们提供了占位符,以便我们在ASP.NET页面中写入逻辑,它们分别是:InitLoadValidateRenderUnload。你可以通过记住单词SILVER来记忆这几个事件,S—Start(没有任何意义,仅仅是为了形成一个单词),I(Init)、L(Load)、V(Validate)、E(Event)、R(Render)。
  • 第四步(M:HttpModule):一旦页面对象执行结束并从内存中被卸载,HttpModule提供了提交返回页面的执行事件,同样,在这些事件中也可以被注入自定义的返回处理逻辑。这里有4个重要的提交处理事件:PostRequestHandlerExecuteReleaserequestStateUpdateRequestCache以及EndRequest

下图形象地展示了上面的四个步骤:

对于执行HttpApplication的ProcessRequest方法这个过程可以看成一个管道,要先后按照顺序执行19个委托事件,其中第八个时,创建 被请求的页面对象,第11到12事件之间,执行了被创建的页面类对象的ProcessRequest方法

什么是请求管道?

请求管道就是把Application的一系列事件串联成一条线,这些事件按照排列的先后顺序依次执行,事件处理的对象包括HttpModule、HttpHandler、ASP.NET Page

熟悉请求管道实现程序运行的全过程:

  • BeginRequest:开始处理请求
  • AuthenticateRequest:授权验证请求,获取用户授权信息
  • PostAuthenticateRequest:获取成功
  • AunthorizeRequest:授权,一般来检查用户是否获得权限
  • PostAuthorizeRequest:获得授权
  • ResolveRequestCache:获取页面缓存结果
  • PostResolveRequestCache:已获取缓存
  • PostMapRequestHandler:创建页面对象
  • AcquireRequestState:获取Session-----先判断当前页面对象是否实现了IRequiresSessionState接口,如果实现了,则从浏览器发来的请求报文体中获得SessionID,并到服务器的Session池中获得对应的Session对象,最后赋值给HttpContext的Session属性
  • PostAcquireRequestState:获得Session
  • PreRequestHandlerExecute:准备执行页面对象,执行页面对象的ProcessRequest方法
  • PostRequestHandlerExecute:执行完页面对象了
  • ReleaseRequestState:释放请求状态
  • PostReleaseRequestState:已释放请求状态
  • UpdateRequestCache:更新缓存
  • PostUpdateRequestCache:已更新缓存
  • LogRequest:日志记录
  • PostLogRequest:已完成日志
  • EndRequest完成

详解ASP.NET页面事件

在上面的部分中,我们已经了解了一个ASP.NET页面请求事件的整体流程。那么,在其中一个最重要的部分就是ASP.NET页面,但是我们并没有对其进行详细讨论

每一个ASP.NET页都有2个部分:一个是在浏览器中进行显示的部分,它包含了HTML标签、viewstate形式的隐藏域 以及 在HTML input中的数据。当这个页面被提交到服务器时,这些HTML标签会被创建到ASP.NET控件,并且viewstate还会和表单数据绑定在一起。一旦你在后置代码中得到所有的服务器控件,你可以执行和写入你自己的逻辑并呈现给客户浏览器。

当页面进行回发时,如点击按钮,以上事件都会重新执行一次,这时的执行顺序为:

  • OnPreInit
  • OnInit
  • OnInitComplete
  • OnPreLoad
  • Page_Load
  • OnLoad
  • Button_Click
  • OnLoadComplete
  • OnPreRender

ASP.Net请求小周期的更多相关文章

  1. [译] ASP.NET 生命周期 – ASP.NET 请求生命周期(二)

    ASP.NET 请求生命周期 全局应用类也可以用来跟踪每个独立请求的生命周期,包括请求从 ASP.NET 平台传递到 MVC 框架.ASP.NET 框架会创建一个定义在 Global.asax 文件中 ...

  2. [译] ASP.NET 生命周期 – ASP.NET 请求生命周期(四)

    不使用特殊方法来处理请求生命周期事件 HttpApplication 类是全局应用类的基类,定义了可以直接使用的一般 C# 事件.那么使用标准 C# 事件还是特殊方法那就是个人偏好的问题了,如果喜欢, ...

  3. [译] ASP.NET 生命周期 – ASP.NET 请求生命周期(三)

    使用特殊方法处理请求生命周期事件 为了在全局应用类中处理这些事件,我们会创建一个名称以 Application_ 开头,以事件名称结尾的方法,比如 Application_BeginRequest.举 ...

  4. 如何确定asp.net请求生命周期的当前处理事件

    1 首先在全局应用程序里面添加如下代码 using System; using System.Collections.Generic; using System.Linq; using System. ...

  5. 详解ASP.NET MVC的请求生命周期

    本文的目的旨在详细描述asp.net mvc请求从开始到结束的每一个过程. 我希望能理解在浏览器输入url并敲击回车来请求一个asp.net mvc网站的页面之后发生的任何事情. 为什么需要关心这些? ...

  6. 【深入ASP.NET原理系列】--ASP.NET请求管道、应用程序生命周期、整体运行机制

    微软的程序设计和相应的IDE做的很棒,让人很快就能有生产力..NET上手容易,生产力很高,但对于一个不是那么勤奋的人,他很可能就不再进步了,没有想深入下去的动力,他不用去理解整个框架和环境是怎么执行的 ...

  7. ASP.NET MVC的请求生命周期

    我希望能理解在浏览器输入URL并敲击回车来请求一个ASP.NET MVC网站的页面之后发生的任何事情. 为什么需要关心这些?有两个原因.首先是因为ASP.NET MVC是一个扩展性非常强的框架.例如, ...

  8. 详解ASP.NET MVC应用程序请求生命周期

    ------转载当一个ASP.NET MVC应用程序提出请求,为了响应请求,包含一些请求执行流程步骤! 在ASP.NET MVC应用程序Http request 和Http response 过程中, ...

  9. ASP.NET请求管道、应用程序生命周期、整体运行机制

    我们知道在ASP.NET中,若要对ASP.NET应用程序进行 初始化并使它处理请求,必须执行一些处理步骤,熟悉应用程序生命周期非常重要,这样才能在适当的生命周期阶段编写代码,达到预期的效果.永远不要做 ...

随机推荐

  1. [Angular] Omit relative path by set up in tsconfig.json

    For example, inside you component you want to import a file from two up directory: import store from ...

  2. POJ 题目2823 Sliding Window(RMQ,固定区间长度)

    Sliding Window Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 46507   Accepted: 13442 ...

  3. [Nuxt] Display Vuex Data Differently in Each Page of Nuxt and Vue.js

    You often use the same data in different ways across pages. This lesson walks you through setting up ...

  4. POJ 3100 Root of the Problem || 1004 Financial Management 洪水!!!

    水两发去建模,晚饭吃跟没吃似的,吃完没感觉啊. ---------------------------分割线"水过....."--------------------------- ...

  5. 27、从零写UVC驱动之分析数据传输(设置ubuntu通过串口打印,指定打印到文件,ubuntu切换root用户)

    A. 设置ubuntu让它从串口0输出printk信息a. 设置vmware添加serial port, 使用文件作为串口(在vmware中设置,文件是保存在windows中)b. 启动ubuntu, ...

  6. [Angular2 Form] Check password match

    Learn how to create a custom validator to check whether passwords match. <h1>password match< ...

  7. Helloworld之Spring依赖注入/控制反转(DI/IoC)版

    Helloworld之Spring依赖注入/控制反转(DI/IoC)版 作者:雨水, 日期:2014-10-29 摘要:本文主要用于培训刚開始学习的人理解Spring中的依赖注入的基本概念. 先介绍依 ...

  8. Swift3.0 功能二 (表情键盘与图文混排)

    随着iOS越来越多表情键盘以及图文混排的需求,本文运用Swift3.0系统的实现其功能以及封装调用方法,写的不好,如有错误望各位提出宝贵意见,多谢 项目源码地址: 相关知识点都有标识 项目源码地址 废 ...

  9. 在Linux上安装及配置MariaDB

    安装MariaDB 1.切换到root用户,首先执行rpm -qa | grep -i mysql检查一下是否有已安装的与MySQL相关的东西,如果有,使用rpm -e --nodeps mysql* ...

  10. JAVA学习路线图---(JAVA1234) 分类: B1_JAVA 2013-10-05 10:22 502人阅读 评论(1) 收藏

    转自:http://blog.csdn.net/pplcheer/article/details/12276999 第一阶段-Java基础        这一阶段很重要,关系到你后面阶段的学习,所以务 ...