考虑使用async编写的ASP .Net MVC应用程序。碰巧异步在顶层和底层使用,但有一些间隙(例如.Result调用)会导致死锁。
我听说.ConfigureAwait(false)
可能有所帮助,但我不确定如何。所以问题是:如何使用.ConfigureAwait(false)
来防止死锁?
这个应用程序有一个将表示层与业务逻辑分开的类。我想让所有业务逻辑方法返回.ConfigureAwait(false)
任务。这是正确的还是足够的?
答案 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
对现有的同步数据访问层逐步进行此类转换。