【问题标题】:Async/Await in WebForms - How does the continuation run before the page lifecycle ends?WebForms 中的 Async/Await - 在页面生命周期结束之前如何继续运行?
【发布时间】:2013-01-23 07:09:51
【问题描述】:

我一直在 WebForms 中测试异步,有一次,我的问题不是关于如何做某事,而是关于已经工作的东西如何工作。这是我的测试代码:

protected override void OnPreRender(EventArgs e)
{
    Response.Write("OnPreRender<Br>");
}
protected override void OnPreRenderComplete(EventArgs e)
{
    Response.Write("OnPreRenderComplete<Br>");
}
protected async override void OnLoadComplete(EventArgs e)
{
    Response.Write("OnLoadComplete<br>");
    var t1 = Task.Factory.StartNew(() => {
        System.Threading.Thread.Sleep(2000);
        return 1;
    });

    //This actually does run:
    Response.Write((await t1).ToString());
}

所以我的任务暂停了一会儿,然后写出结果。我的问题是 - 我不希望这会起作用,因为 OnLoadComplete 方法已经产生了控制权 - 我希望页面实际上完成渲染并在我的任务返回之前返回给客户端。

实际输出为:

OnLoadComplete
OnPreRender
1OnPreRenderComplete

因此很明显,OnLoadComplete 方法产生了控制权,以便 OnPreRender 可以运行,然后控制权返回给 OnLoadComplete。我的预期结果是“1”永远不会打印,因为随后的事件会触发,并且页面的线程会被杀死,或者在发送响应后会发生任务后写入。我想,鉴于上述情况,即使我延迟 10 秒,结果也完全一样,这并不奇怪。

我假设 WebForm 引擎中有一些连接可确保在页面生命周期的下一阶段继续之前完成所有等待项。有谁知道这是怎么发生的?我害怕在需要在其他事件之前完成的方法中使用async/await,因为担心继续为时已晚,但如果是内部处理,那我就不用担心了。

【问题讨论】:

    标签: asp.net webforms async-await


    【解决方案1】:

    对于 ASP.NET,您应该只在 .NET 4.5 上使用 async 方法。我会在最后解释原因。

    我有an article on SynchronizationContext,它有助于填补关于它如何在 ASP.NET 上工作的空白。首先,请注意 ASP.NET 很久以前就支持异步操作(.NET 2.0 IIRC)。您可以通过几种不同的方式注册异步操作,但对于此描述,我们将重点关注SynchronizationContext.OperationStarted

    ASP.NET 为每个请求创建一个SynchronizationContext,并且它知道在所有注册的操作都完成之前请求是不完整的(通过调用SynchronizationContext.OperationCompleted)。 Event-based asynchronous pattern components(如BackgroundWorker)会在SynchronizationContext启动和完成时自动通知。

    同样,async void 方法(新的task-based asynchronous pattern)将在它们启动和完成时自动通知SynchronizationContext。因此,当您将 OnLoadComplete 重写为 async void 方法时,编译器会为您插入代码,该代码将在开头调用 OperationStarted 并在完成时调用 OperationCompleted

    到目前为止一切顺利 - ASP.NET 现在知道要保持请求处于活动状态,直到该请求的所有异步操作都完成为止。即使没有线程处理请求也是如此。

    现在需要注意的是:.NET 4.5 之前的 ASP.NET 将在 request 级别处理此问题。在 ASP.NET 4.5 中,生命周期管道变得更加智能,因此它会延迟页面生命周期,直到异步操作完成。对于旧的 ASP.NET,“pre”处理程序将在管道中的那个点开始,但可能要到稍后才能完成。新的 ASP.NET 将延迟页面执行的其余部分,以确保 async 处理程序在生命周期中继续之前完成。

    此外,ASP.NET 4.5 将检测您是否使用了不应有的 async 处理程序,并将通知您错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-12-13
      • 2019-11-16
      • 2012-01-13
      • 1970-01-01
      • 2019-05-24
      • 1970-01-01
      • 2021-04-14
      • 1970-01-01
      相关资源
      最近更新 更多