HttpApplication异步事件(例如使用AddOnEndRequestAsync
和朋友注册的事件)在多大程度上是异步的?在转移到下一个事件之前,IIS是否等待为特定事件触发的所有异步事件,或者它们是否会“触发并忘记”?
答案 0 :(得分:4)
在集成管道模式下运行时,我不清楚确切的工作方式,但我可以告诉你我对非集成案例的看法,并且语义应该保持不变。
简短的回答是每个事件处理程序都是串行触发的,无论是同步的还是异步的,并且在上一次完成之前不会触发下一个事件处理程序。
您可以通过源代码跟踪此内容。
请求进入并存储在队列中。通常,当HttpRuntime
将请求出列时,它会通过调用HttpApplication
方法为请求初始化InitInternal
,并将HttpContext
作为参数传递。
HttpApplication.InitInternal
为非集成模式案例初始化一个新的HttpApplication.ApplicationStepManager
类。然后,您可以看到它调用BuildSteps
方法。这将创建一个ArrayList
来存储步骤,构造并存储所有步骤。具体而言,这些步骤是IExecuteStep
接口的实现。最后,当添加所有步骤时,通过将列表复制到数组并将其保存到成员var _execSteps
中来最终确定列表。
这些步骤有几个来源,但您最常用的是HttpApplication.CreateEventExecutionSteps
,它采用事件类型(开始请求,授权等)和步骤数组来添加其步骤如果你深入研究CreateEventExecutionSteps
,你可以看到它分别从IExecuteStep
和AsyncEvents
表中为它知道的每个异步和同步处理程序添加Events
。 IExecuteStep
界面本身基本上由Execute
方法和CompletedSynchronously
标记组成。
现在,暂停并回顾其中一个Add方法,例如您提到的那个AddOnEndRequestAsync
,您可以看到它将有关异步处理程序的信息添加到AsyncEvents
表。然后,CreateEventExecutionSteps
将遍历此表格,并为每个添加的处理程序构建AsyncEventExecutionStep
。
返回请求流程。在HttpRuntime
初始化请求的HttpApplication
后,它会调用BeginProcessRequest
方法,该方法会触发ResumeSteps
。
ResumeSteps
是重要的一个,您可以在其中查看步骤的使用方式以及异步情况下的等待策略。您可以看到它在执行步骤数组中维护_currentStepIndex
。最后,您会看到它从数组中获取下一步并调用其Execute
方法。如果该步骤报告其执行CompletedSynchronously
,则它会循环并再次运行。如果没有,它会让方法完成并进入异步深渊。
要了解在此异步情况下会发生什么,您必须查看为异步处理程序创建的AsyncEventExecutionStep
实现。在其Execute
实现中,您会看到它触发begin处理程序并传入完成回调。在构造函数中,您将此回调初始化为最终再次调用... HttpApplication.ResumeSteps
的方法!
所以它继续运行,执行步骤,同步或异步,直到数组溢出,此时它“完成”请求处理。
关键是,您可以清楚地看到转换为您添加的事件处理程序的步骤是逐个执行的,无论是同步还是异步,在当前步骤完成之前,以下步骤都不会执行。您的问题是事件是否以这种方式逐个处理,但正如您所看到的,实际上它更加精细,每个事件处理程序都以这种方式处理,因此每个事件都可以获得对HttpContext的同步访问,并且可以在没有事件的情况下运行担心他们是否还处于管道的“正确阶段”。
显然,源代码中有其他细节,yada yada,但这是要点。