[asp.net-mvc]异步调用永远不会返回在 Asp.Net MVC 中

发布时间: 2017/3/25 0:35:01
注意事项: 本文中文内容可能为机器翻译,如要查看英文原文请点击上面连接.

我返回一个列表,其中基本上要求两个异步操作︰

[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 请求 (从客户端),但在前端它永远不会返回。是否有任何死锁?

解决方法 1:

建立我从几个评论的答复和 @usr 的答案︰

  • Data在上面的代码实际上是 IEnumerable<Task<ProductModel>> ,不 IEnumerable<ProductModel> 。这是因为 lambda 传递给 Selectasync
  • 最有可能的 JSON 序列化程序是复习这种结构和枚举的属性上 Task<ProductModel> 实例,包括 Result

我解释我的博客为什么访问 Result 将导致死锁在这种情况下。简单地说,这是因为 async lambda 将尝试恢复后在 ASP.NET 请求上下文上的执行其 await 。但是,ASP.NET 请求上下文被阻止在调用 Result ,锁定内部直到那请求上下文的线程 Task<T> 完成。因为 async lambda 不能恢复,它不能完成这项任务。所以这两件事互相等待,和你出现了经典的死锁。

有一些建议使用 await Task.WhenAll ,我通常会赞成的。然而,在这种情况下您使用实体框架,得到了此错误︰

第二个操作开始前一个异步操作完成前此上下文。

这是因为 EF 无法执行多个异步调用同时在相同的 db 范围内。有几种方法解决这个;一是使用多个数据库上下文 (本质上是多个连接) 兼做电话。国际海事组织一个简单的方法就是要按顺序而不是并发的异步调用︰

[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);
}
赞助商