首页 > 代码库 > 并发请求时,HttpApplication的事件是如何执行的?

并发请求时,HttpApplication的事件是如何执行的?

1 疑问:

    如果系统里注册了一个HttpModule,在BeginRequest里编写了代码,执行时如果卡住,会影响其他请求的执行吗?

查阅MSDN的解释:

http://msdn.microsoft.com/zh-cn/library/system.web.httpapplication(VS.80).aspx

 

HttpApplication 类的实例是在 ASP.NET 基础结构中创建的,而不是由用户直接创建的。HttpApplication 类的一个实例在其生存期内被用于处理多个请求,但它一次只能处理一个请求。这样,成员变量才可用于存储针对每个请求的数据。

根据这里的描述不能回答如果有2个Request 同时进来怎么办?先执行Request1的第一个事件BeginRequest ,完成后处理Request2的第一个事件BeginRequest ?如果处理Request2的BeginRequest事件卡住了,其他Request还能不能继续往下执行?

2 一个请求执行的大体流程

ASP.net 执行请求的第一步是HttpRumtime.ProcessRequest方法,然后内部会到底HttpApplication的实例,然后执行HttpApplication. ProcessRequest的方法,最后调用HttpHandler的ProcessRequest方法。

反射看下源代码,HttpRuntime的核心函数:

 

HttpApplication的BeginProcessRequest函数

ResumeSteps函数:

_execSteps的数组的数据何时添加进去的呢?是在HttpApplication初始化的时候:

先看在哪里把当前的HttpApplication放入freeList中,定位到ResumeSteps函数的最末尾:

内部还写了个小逻辑,不保留超过100个HttpApplication的实例。

接着我们看函数 InitInternal,看我们的_execStep数组是怎么初始化的 :

在每个Module里都会对传进来的实例进行事件注册。比如:

 

接下来就把各个事件对应的委托都编入Steps里:

查看CreateEventExecutionSteps函数:

在调试的时候是可以看到编好的Steps里有哪些:

3总结下:总体流程图如下:

  • HttpRumtime.ProcessRequest被调用
    • 获得HttpApplication的实例
      • 从空闲列表中取实例或产生新HttpApplication的实例
      • 调用InitInternal方法初始化
        • 调用InitModule来初始化
          • 得到各个HttpModule
          • 调用HttpModule的Init方法
          • 各个HttpModule在init方法里定义事件对应的委托
        • 将系统内置的处理步骤编入_execSteps中
        • 将各个事件的对应的委托编入_execSteps中
    • 调用HttpApplication.BeginProcessRequest
      • 调用ResumeStep方法
        • 逐个执行_exeSteps数组里的步骤
        • 执行完后,回收此实例

     

4 回到我的疑问:

    同时有2个Request 进来,系统会产生2个HttpApplication的实例,每个实例处理一个,2者之间不会相互影响。

再看MSDN的原话:

HttpApplication 类的实例是在 ASP.NET 基础结构中创建的,而不是由用户直接创建的。HttpApplication 类的一个实例在其生存期内被用于处理多个请求,但它一次只能处理一个请求。这样,成员变量才可用于存储针对每个请求的数据。

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

什么叫被用于处理多个请求?

就是这个实例会回收,处理完这个请求后,可以再处理其他请求。

什么叫一次只能处理一个请求?如果有多个请求呢?

多个请求就产生多个实例呗!

怎么控制事件的执行顺序?

内部编一个Step的列表,按固定的顺序添加进去,然后顺序的执行一遍呀。

看来我有这个疑问的关键在于受了Application的实例只有1个的影响,所以看了MSDN的这句话,半天也没理解一下子说处理多个请求,一下又说处理一个请求,看了源代码,终于明白他为什么一下子写可以处理多个请求,一下又写只能处理1个请求。对,一个Web应用程序只有1个Application实例,但是那是指HttpApplication上的Application属性,不是指HttpApplication的实例只有1个,同时并发请求有多少个,就有多少个HttpApplication的实例。

 

5 调试证明HttpApplication实例是会产生多个,也能被重用:

编写一个HttpModule,代码如下:

public class HttpModule1 : IHttpModule{    public void Dispose()    {    }    public void Init(HttpApplication context)    {        context.BeginRequest += new EventHandler(context_BeginRequest);    }    void context_BeginRequest(object sender, EventArgs e)    {        if (((HttpApplication)sender).Request.RawUrl.EndsWith("Default.aspx"))        {            Thread.Sleep(20000);        }    }}

 把它配置到Web.Config 中去:

        <httpModules>            <add name="HttpModule1" type="HttpModule1"/>        </httpModules>

简单添加2个ASPX文件:Default.aspx 和 Test.aspx。然后启动调试:

1)请求Default.aspx

第一个Default.aspx请求到来,实例是971734,让它继续执行,卡住 。

2)再开一个浏览器,请求Test.aspx

第二个Test.aspx请求到来,实例是45150396,与之前的并不一致,说明有并发请求到来时,有多个HttpApplication的实例。

3)过了20秒后,再请求Test.aspx:

实例又变回971734 ,说明之前执行Default.aspx的实例没有销毁,这里又重用了。

并发请求时,HttpApplication的事件是如何执行的?