【问题标题】:我可以在 .NET 4.7.2 Web API 中删除 ConfigureAwait(false) 吗?
【发布时间】:2023-03-30 23:06:01
【问题描述】:

我正在检查一些使用 .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);
      }
  }

我已经读到best practice 不会在应用程序代码中使用ConfigureAwait,以便继续执行捕获的同步上下文,因为可能需要状态associated with the captured context。但是,通常我们应该使用ConfigureAwait(false),这样我们就不会不必要地继续捕获的同步上下文。

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

然后我读到了deadlocksdoesn't matter when using ASP.NET Core(虽然我不是)。

我添加了一个断点并检查了SynchronizationContext.Current,即null

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

【问题讨论】:

  • 我写了a lengthy answer about this。不要在应用程序代码中使用ConfigureAwait(false)。死锁仅在您同步等待异步方法时发生,无论如何您都不应该这样做。

标签: .net asp.net-web-api async-await


【解决方案1】:

我已阅读最佳实践是不在应用程序代码中使用 ConfigureAwait,以便继续执行捕获的同步上下文,因为可能需要与捕获的上下文相关联的状态。但是,通常我们应该使用 ConfigureAwait(false),这样我们就不会不必要地继续捕获的同步上下文。

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

所以我的想法是我们不想在这个 Web API 代码的任何地方调用 ConfigureAwait(false)。

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

然后我读到了死锁...

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

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

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

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

实际上,这是非常有问题的。请查看 this article 并确保您已完成在 ASP.NET 上使用 async 代码的所有先决条件。特别是,您必须对httpRuntime.targetFrameworkaspnet:UseTaskFriendlySynchronizationContext 进行适当的设置。

【讨论】:

    【解决方案2】:

    您应该从 ASP.NET 管道代码中删除 ConfigureAwait(false) 调用。这包括控制器操作方法。

    如果后面的代码使用HttpContext.Current,那么它的值就是null

    【讨论】:

    • HttpContext.Currentnull 调用之前,实际上是在进入方法时。
    • 哪些上下文存在不可用的风险?
    • 你有没有调用ConfigureAwait(false)的中间件? HttpContext.Current null 在控制器构造函数中吗?
    • 没有自定义中间件。 HttpContext.Current 是控制器构造函数中的 null
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-27
    • 1970-01-01
    相关资源
    最近更新 更多