Reputation: 7412
I have a method which is Async "upstream". I'm trying to follow best practice and go all-in qith async all the way up the stack.
Within a Controller action within MVC I predictably hit the deadlock issue If I rely on .Result().
Changing the Controller action to async seems to be the way to go, though the issue is that the async method is called multiple times within a lambda.
How can I await on a lamda that returns multiple results?
public async Task<JsonResult> GetLotsOfStuff()
{
IEnumerable<ThingDetail> things= previouslyInitialisedCollection
.Select(async q => await GetDetailAboutTheThing(q.Id)));
return Json(result, JsonRequestBehavior.AllowGet);
}
You can see I have tried making the lambda async, but this just gives a compiler exception:
Cannot convert source type
System.Collections.Generic.IEnumerable<System.Threading.Tasks.Task<ThingDetail>
to target typeSystem.Collections.Generic.IEnumerable<ThingDetail>
Where am I going wrong here?
Upvotes: 24
Views: 16024
Reputation: 68660
Thing
s into a collection of Task<Thing>
s.Task.WhenAll
and await it.Thing[]
public async Task<JsonResult> GetLotsOfStuff()
{
IEnumerable<Task<ThingDetail>> tasks = collection.Select(q => GetDetailAboutTheThing(q.Id));
Task<int[]> jointTask = Task.WhenAll(tasks);
IEnumerable<ThingDetail> things = await jointTask;
return Json(things, JsonRequestBehavior.AllowGet);
}
Or, succinctly and using type inference:
public async Task<JsonResult> GetLotsOfStuff()
{
var tasks = collection.Select(q => GetDetailAboutTheThing(q.Id));
var things = await Task.WhenAll(tasks);
return Json(things, JsonRequestBehavior.AllowGet);
}
Fiddle: https://dotnetfiddle.net/78ApTI
Note: since GetDetailAboutTheThing
seems to return a Task<Thing>
, the convention is to append Async
to its name - GetDetailAboutTheThingAsync
.
Upvotes: 35