我返回一个基本上调用两个异步操作的列表:
[HttpPost]
public ActionResult List(DataSourceRequest command, ProductListModel model)
{
var categories = _productService.GetAllProducts(model.SearchProductName,
command.Page - 1, command.PageSize);
var gridModel = new DataSourceResult
{
Data = categories.Select(async x =>
{
var productModel = x.ToModel();
var manufacturer = await _manufacturerService.GetManufacturerById(x.ManufacturerId);
var category = await _categoryService.GetCategoryById(x.CategoryId);
productModel.Category = category.Name;
productModel.Manufacturer = manufacturer.Name;
return productModel;
}),
Total = categories.TotalCount
};
return Json(gridModel);
}
这是一个 ajax 请求(来自客户端),但在前端永远不会返回。有没有死锁?
最佳答案
根据几条评论和@usr 的回答建立我的答案:
-
Data
上面代码中实际上是IEnumerable<Task<ProductModel>>
, 不是IEnumerable<ProductModel>
.这是因为 lambda 传递给了Select
是async
. - 很可能,JSON 序列化程序遍历此结构并枚举
Task<ProductModel>
上的属性实例,包括Result
.
我在我的博客上解释why accessing Result
will cause a deadlock在这种情况下。简而言之,这是因为 async
lambda 将在其 await
之后尝试在 ASP.NET 请求上下文上恢复执行.但是,ASP.NET 请求上下文在调用 Result
时被阻止,锁定该请求上下文中的线程,直到 Task<T>
完成。自 async
lambda 无法恢复,它无法完成该任务。所以这两件事都在等待对方,你会遇到一个典型的死锁。
有一些使用建议await Task.WhenAll
,我通常会同意。但是,在这种情况下,您使用的是 Entity Framework 并收到此错误:
A second operation started on this context before a previous asynchronous operation completed.
这是因为 EF 无法在同一个数据库上下文中同时执行多个异步调用。有几种方法可以解决这个问题;一种是使用多个数据库上下文(本质上是多个连接)来同时进行调用。 IMO 一种更简单的方法是按顺序而不是同时进行异步调用:
[HttpPost]
public async Task<ActionResult> List(DataSourceRequest command, ProductListModel model)
{
var categories = _productService.GetAllProducts(model.SearchProductName,
command.Page - 1, command.PageSize);
var data = new List<ProductModel>();
foreach (var x in categories)
{
var productModel = x.ToModel();
var manufacturer = await _manufacturerService.GetManufacturerById(x.ManufacturerId);
var category = await _categoryService.GetCategoryById(x.CategoryId);
productModel.Category = category.Name;
productModel.Manufacturer = manufacturer.Name;
data.Add(productModel);
}
var gridModel = new DataSourceResult
{
Data = data,
Total = categories.TotalCount
};
return Json(gridModel);
}
关于c# - 异步调用永远不会在 Asp.Net MVC 中返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33185932/