在WebApi或MVC控制器中使用ConfigureAwait(false)是否存在任何危险?

70

假设我有两种场景:

1)WebApi 控制器

    [System.Web.Http.HttpPost]
    [System.Web.Http.AllowAnonymous]
    [Route("api/registerMobile")]
    public async Task<HttpResponseMessage> RegisterMobile(RegisterModel model)
    {
        var registerResponse = await AuthUtilities.RegisterUserAsync(model, _userService, User);
        if (registerResponse.Success) {
            var response = await _userService.GetAuthViewModelAsync(model.Username, User);
            return Request.CreateResponse(HttpStatusCode.OK, new ApiResponseDto() { Success = true, Data = response });
        }
        else {
            return Request.CreateResponse(HttpStatusCode.OK, registerResponse);
        }

    }

2) MVC 控制器

    [Route("public")]
    public async Task<ActionResult> Public()
    {
        if (User.Identity.IsAuthenticated)
        {
            var model = await _userService.GetAuthViewModelAsync(User.Identity.Name);
            return View("~/Views/Home/Index.cshtml", model);
        }
        else
        {
            var model = await _userService.GetAuthViewModelAsync(null);
            return View("~/Views/Home/Index.cshtml", model);
        }
    }

我一直在研究何时应该使用 ConfigureAwait,看起来我应该在所有非直接与UI相关的异步调用中使用 ConfigureAwait(false)。但是我不知道这意味着什么...这些 await 调用是否都应该使用 .ConfigureAwait(false)

我正在寻找关于何时应该使用它的明确指南。

这个问题不同于 Best practice to call ConfigureAwait for all server-side code - 我正在寻找有关WebApi和MVC上下文中此方法用例的简单答案,而不是C#的一般性解释。


@MickyD,看到这里,我看到“// 当在GUI或ASP.NET上下文中调用此方法时会导致死锁。”-难道WebApi和MVC不是利用.NET上下文吗?在上述情况下,您会怎么做以及为什么? - SB2055
1
@MickyD 我已经读了好几遍,但仍然不清楚。我一定很蠢。“在ASP.NET中的问题是当线程恢复方法时是否进入请求上下文。” - 我需要在上述场景中执行此操作吗? - 我肯定不是唯一一个会从这里得到基于简单示例的响应的人...请不要将其标记为关闭,因为这个问题更适用于API和MVC,而不是通用的C#。 - SB2055
2
这篇文章可能更有趣...另一方面,如果您/您的团队非常有纪律性,从不使用全局值(如当前 Http 上下文或当前文化),则两种方式都可以。此外,https://dev59.com/uWYr5IYBdhLWcg3wq7-I 是您要寻找的答案 - 不太清楚您的问题有何不同(或者为什么您期望得到任何其他答案而不是在服务器端代码中调用 ConfigureAwait(false) 没有意义)。 - Alexei Levenkov
5
这里的声明“no point to call ConfigureAwait(false)”是我感到困惑的原因。缺乏明确的、基于示例的答案,指导相互矛盾。 - SB2055
这里不是一个规模问题吗?在长时间运行的API调用中释放UI线程以服务更多请求?使用ConfigureAwait(false)的操作将在下一个可用线程上恢复,而不是保持最初发出请求的线程。虽然每个请求没有性能提高,但可以增加规模,允许更多请求完成,而不是长时间运行的任务占用有限的线程池中的线程。 - Observer
4个回答

90
似乎我应该在所有不直接与UI相关的异步调用上使用ConfigureAwait(false)。 并非如此。这个指南在这里没有意义,因为没有UI线程。 传递给ConfigureAwait的参数是continueOnCapturedContext,它更清楚地解释了情况。每当该异步方法的其余部分不依赖于当前上下文时,都需要使用ConfigureAwait(false)。 在ASP.NET 4.x中,“上下文”是请求上下文,其中包括像HttpContext.Current和culture之类的内容。此外 - 这是未记录的部分 - 许多ASP.NET帮助程序方法确实依赖于请求上下文。 (旁注:ASP.NET Core不再有“上下文”) 我没有听到任何关于这个的坚定指导,但我认为可以这样做。 在我的代码中,我从不在控制器操作方法中使用ConfigureAwait(false),以便它们已经在请求上下文中完成。这对我来说似乎更正确。

2
Stephen,这个有更新吗?我正在编写asp.net core mvc的控制器代码,想知道使用/不使用ConfigureAwait(false)的影响。你的附注并没有真正帮助到我——如果ASP.NET Core没有上下文,那么这是否意味着我应该使用ConfigureAwait(false)? - David Clarke
3
@DavidClarke:由于没有上下文的存在,ConfigureAwait(false)是没有效果的。更多信息请参考:https://blog.stephencleary.com/2017/03/aspnetcore-synchronization-context.html - Stephen Cleary
@Landerah:据我所知,目前还没有这样的功能。即使有,它也只是一个实现细节,可能会在下一个版本中发生变化。而且现在这个阶段,这并不是很重要,因为ASP.NET Core才是未来。 - Stephen Cleary
1
@kuldeep:ConfigureAwait 配置 await。如果没有 await,则不会执行任何操作。 - Stephen Cleary
2
@kuldeep:不,这将是“点火并忘记”,这几乎永远不是您想要的。如果您需要更多信息,请随时提出自己的问题。 - Stephen Cleary
显示剩余8条评论

1
如果ASP.NET Core应用程序中没有实际上下文,将 .ConfigureAwait(false) 添加到控制器的可等待方法中不会对其造成损害或好处。
但是,如果在未来可能会出现某些类似于ASP.NET 4中需要考虑上下文的情况,则情况将有所不同。我们不能冒险在不同的上下文中运行,除非我们不关心它(在这种情况下,我们可以使用任何可用于处理的线程,从而可能提高性能)。
我的选择是即使未使用,也要添加 ConfigureAwait(false)。

“它不应该有任何好处或坏处” - 实际上,由于它不必为继续执行切换同步上下文,因此存在性能提升。 - David Klempfner

-4

你可以在公共操作MVC Controller 上使用 ConfigureAwait,它有助于防止如果你的_userService.GetAuthViewModelAsync一直等待时发生死锁。

如果异步服务一直等待,它可能会引发死锁,从而阻塞 UI 的 httpcontext。

请查看以下链接以了解此情况:

http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html


-7

在控制器中使用ConfigureAwait(false) 对我来说听起来不太好,因为它会让主线程等待操作完成。我想到的最好方式是在您的服务/业务层和持久化层中使用它。


3
ConfigureAwait(false)并不会禁用异步等待!它只是意味着在指定的异步方法完成时使用可用的任何上下文来恢复执行。 - Shishir Gupta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接