使用 LegacyAspNetSynchronizationContext 对 .net 4.7 中的异步/等待代码有什么影响?

What effect does using LegacyAspNetSynchronizationContext have with async / await code in .net 4.7?

我正在将遗留 Asp.Net WebForms 项目升级到 .net 4.7。

在我的配置中,我将目标框架设置为 4.7 并将同步上下文设置为使用新的 AspNetSynchronizationContext(尽管我相信如果省略后者是隐含的)以允许新的 async / await 方法工作,例如

<httpRuntime targetFramework="4.7" />
...
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />

但后来我发现 很多 代码如下:

var myTask = DoSomethingAsync();
return myTask.Result;

未等待任务结果导致应用程序挂起。

如果我更改配置以使用 LegacyAspNetSynchronizationContext ...

<add key="aspnet:UseTaskFriendlySynchronizationContext" value="false" />

...遗留的非等待代码再次工作,新的 async/await 方法 出现 工作。我说 "appear" 正如我在 this MSDN article 中读到的那样:

the behavior of async / await is undefined in ASP.NET unless this switch has been set

为什么未定义?这是否意味着该行为不可预测或根本行不通?

如果我有如下代码片段,当它在 LegacyAspNetSynchronizationContext 中被调用时将会或可能发生什么?

public async Task<bool> DoSomethingElseAsync()
{
    return await CallSomeApiAsync().ConfigureAwait(false);
}

使用 LegacyAspNetSynchronizationContext 意味着您在使用任务时不会获得定义的行为;遗留的同步模型不是为与任务调度一起工作而构建的。如果您想在 ASP.NET.

中使用任务,您 必须 使用新的同步上下文
var myTask = DoSomethingAsync();
return myTask.Result;

此代码块 Task。在 运行 Task 上调用 Wait()Result 将阻塞调用线程,直到 Task 完成。

你不能安全地阻止任务,除非你知道:

  • 任务已经完成(在这种情况下你并没有真正阻止)。
  • 同步上下文不会尝试在启动任务的同一线程上恢复。

唯一合理的解决方案是一直使用任务。任何试图阻塞 Task 的方法都应该改为 return a TaskTask<TResult> and await the 运行 Task 代替。