如何防止从死锁中使用async的ASP .Net应用程序?

时间:2014-06-16 02:02:11

标签: c# asp.net-mvc async-await

考虑使用async编写的ASP .Net MVC应用程序。碰巧异步在顶层和底层使用,但有一些间隙(例如.Result调用)会导致死锁。

我听说.ConfigureAwait(false)可能有所帮助,但我不确定如何。所以问题是:如何使用.ConfigureAwait(false)来防止死锁?

这个应用程序有一个将表示层与业务逻辑分开的类。我想让所有业务逻辑方法返回.ConfigureAwait(false)任务。这是正确的还是足够的?

1 个答案:

答案 0 :(得分:2)

使用ConfigureAwait(false)是一种解决方法而非最终解决方案。您可以消除由task.Result引起的死锁,但您仍然会阻止请求线程,从而有效地消除了在服务器端使用async/await的主要优势,这提高了Web应用程序的可伸缩性。

另一个不那么明显的问题是await task.ConfigureAwait(false)之后的延续代码将失去对AspNetSynchronizationContext提供的HTTP请求的环境信息的访问权限(例如,不再HttpContext.Current.Items)。

理想情况下,您应该重构服务/数据层以使用任务,并使用async/await“一直向下”到根方法,这是一种异步控制器方法。这并不困难,只需使用Task<T>代替T进行数据访问接口:

public interface IAsyncData
{
    Task<int> AsyncData { get; }
}

而不是

public interface IData
{
    int Data { get; }
}

然后在实现数据存储库时使用异步Task-based数据访问API,并在实现MVC控制器时使用await data.AsyncData使用data.Data

您可以使用Task.FromResult AsyncData对现有的同步数据访问层逐步进行此类转换。