我正在将一个遗留的 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
方法似乎有效。我说"出现",因为我在这篇 MSDN 文章中读到:
/等待的行为在 ASP.NET 中未定义,除非已设置此开关
为什么它未定义?这是否意味着行为是不可预测的或根本不起作用?
如果我有如下所示的代码片段,那么在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
的方法都应该改为返回Task
或Task<TResult>
,并改为await
正在运行的Task
。