来自 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
。