28

我已经编写了一个自定义的 ASP.NET 控件,并且我刚刚将它更新为具有异步 Load 事件处理程序。现在我收到此错误:

此时无法启动异步操作。异步操作只能在异步处理程序或模块内或在页面生命周期中的某些事件期间启动。如果在执行页面时发生此异常,请确保将页面标记为 <%@ Page Async="true" %>。

该页面确实已经有<%@ Page Async="true" %>标签。所以我认为控件不能有异步加载事件处理程序。

我在哪里可以找到 ASP.NET 网络表单生命周期中允许异步的事件的完整列表?

4

2 回答 2

28

来自 ASP.NET 团队的 Damian Edwards 给出了这样的答案:

如您所见,Web 表单中的异步 void 事件处理程序仅在某些事件上受支持,但实际上仅适用于简单的任务。我们建议将 PageAsyncTask 用于任何真正复杂的异步工作。

来自 ASP.NET 团队的 Levi Broderick 给出了这样的答案:

Web 应用程序中的异步事件本质上是奇怪的野兽。Async void 适用于“一劳永逸”的编程模型。这适用于 Windows UI 应用程序,因为应用程序会一直存在直到操作系统将其杀死,因此无论何时运行异步回调,都可以保证有一个可以与之交互的 UI 线程。在 Web 应用程序中,该模型分崩离析,因为根据定义,请求是瞬态的。如果异步回调恰好在请求完成后运行,则无法保证回调需要与之交互的数据结构仍处于良好状态。因此,为什么一劳永逸(和异步无效)在 Web 应用程序中本质上是一个坏主意。

也就是说,我们做了一些疯狂的体操来尝试让 Page_Load 这样非常简单的事情起作用,但是支持这一点的代码非常复杂,并且没有针对基本场景之外的任何事情进行良好的测试。因此,如果您需要可靠性,我会坚持使用 RegisterAsyncTask。

所以我认为我的问题的答案是:“这是个错误的问题。”

正确的问题是“我应该如何在我的 ASP.NET Web 窗体应用程序中保持异步?” 答案是将此代码段插入到您的 aspx 代码隐藏文件中:

this.RegisterAsyncTask(new PageAsyncTask(async cancellationToken => {
    var result = await SomeOperationAsync(cancellationToken);
    // do something with result.
}));

同样的技巧在 ASP.NET 自定义控件中也有效,只需使用它this.Page.RegisterAsyncTask

于 2013-02-09T23:39:31.470 回答
1

本页解释了异步页面中的生命周期事件处理与 ASP.NET 2.0 中同步页面的处理方式有何不同(图 2 尤其有用):

邪恶的代码:ASP.NET 2.0 中的异步页面

您可能还会发现这个 SO 使用问题(它谈到了相同的错误消息):

async 关键字和 TaskScheduler 的选择

于 2013-02-01T04:36:47.420 回答