我可以在.NET 4.7.2 Web API 中删除ConfigureAwait(false) 吗?

fra*_*tor 2 .net async-await asp.net-web-api

我正在检查一些使用 .NET 4.7.2 的 ASP.NET Web API 代码。

这是一个示例控制器和操作方法:

  public class ThingController : System.Web.Http.ApiController
  {
      // ...

      public async Task<IHttpActionResult> GetValue()
      {
          var value = await _db.GetValue().ConfigureAwait(false);
          return Content(value);
      }
  }
Run Code Online (Sandbox Code Playgroud)

我读到,最佳实践是不在ConfigureAwait应用程序代码中使用,以便继续执行捕获的同步上下文,因为可能存在与捕获的上下文关联的所需状态。然而,一般来说,我们应该使用ConfigureAwait(false)这样的方法,这样我们就不会不必要地继续捕获的同步上下文。

所以我的想法是,我们不想ConfigureAwait(false)在此 Web API 代码中的任何位置进行调用。

然后我读到了有关死锁的内容,并且在使用 ASP.NET Core 时这并不重要(尽管我不是)。

我添加了一个断点并检查了SynchronizationContext.Current哪个是null.

ConfigureAwait(false)我可以安全地删除该项目的所有调用吗?如果不是,在什么情况下应该保留这些调用?

Ste*_*ary 5

我读过,最佳实践是不在应用程序代码中使用ConfigureAwait,以便继续执行捕获的同步上下文,因为可能存在与捕获的上下文关联的所需状态。然而,一般来说,我们应该使用ConfigureAwait(false),这样我们就不会不必要地继续捕获的同步上下文。

我想说最好的做法是在库中使用ConfigureAwait(false),它可以在不同的上下文中使用。对于应用程序代码,ConfigureAwait(false)通常是不必要的。(出于性能原因,有一些高级情况ConfigureAwait(false)是必要的,但这种情况很少见)。

所以我的想法是,我们不想在此 Web API 代码中的任何位置调用ConfigureAwait(false)。

我同意。除了控制器方法之外,我通常会ConfigureAwait(false)在任何可以使用的地方使用,但您可以扩展“不使用ConfigureAwait(false)”规则以包括所有应用程序代码。

然后我读到了死锁......

死锁(如我的博客中所述)需要两个部分:

  1. 单线程上下文。在 ASP.NET 中,SynchronizationContext是单线程上下文。
  2. 在该上下文中阻塞线程,等待一些需要该上下文的代码。这部分通常是由“同步优于异步”反模式引起的。

在您的代码中,没有同步异步,因此无论是否ConfigureAwait(false)使用都不可能出现死锁。

我添加了一个断点并检查了 SynchronizationContext.Current 为 null...HttpContext.Current 在调用之前为 null,实际上在进入该方法时。

实际上,这是非常有问题的。请阅读本文并确保您已完成在 ASP.NET 上使用代码的所有先决条件asynchttpRuntime.targetFramework特别是,您必须对或进行适当的设置aspnet:UseTaskFriendlySynchronizationContext