Building up my answer from several comments and @usr's answer:
Data in the code above is actually IEnumerable<Task<ProductModel>>, not IEnumerable<ProductModel>. This is because the lambda passed to Select is async.
- Most likely, the JSON serializer is going over this structure and enumerating the properties on the
Task<ProductModel> instances, including Result.
I explain on my blog why accessing Result will cause a deadlock in this case. In a nutshell, it's because the async lambda will attempt to resume execution on the ASP.NET request context after its await. However, the ASP.NET request context is blocked on the call to Result, locking a thread inside that request context until the Task<T> completes. Since the async lambda cannot resume, it cannot complete that task. So both things are waiting for each other, and you get a classic deadlock.
There are some suggestions to use await Task.WhenAll, which I would normally agree with. However, in this case you're using Entity Framework and got this error:
A second operation started on this context before a previous asynchronous operation completed.
This is because EF cannot perform multiple asynchronous calls concurrently within the same db context. There are a couple ways around this; one is to use multiple db contexts (essentially multiple connections) to do the calls concurrently. IMO a simpler way is to make the asynchronous calls sequentially instead of concurrently:
[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);
}
awaiting calls when not inside a method that (a) is not marked asasyncand (b) does not returnTask<ActionResult>?async Task<ActionResult>the compiler reports that my method lacksawaitoperator. Even if ii put it, it doesn't work.asyncdelegate. That's the problem by the looks of it. IsDataaTask<T>whereTis thex.ToModel()type?IEnumerable<Task>because of the async delegate passed to.Select(). This means that it will not be waiting for the task to complete. If youawaitthecategories.Select()call by wrapping in aTask.WhenAll(), mark the action asasyncand returnTask<ActionResult>, I believe this should solve your problem