Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use async within a lambda which returns a collection

Tags:

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 type System.Collections.Generic.IEnumerable<ThingDetail>

Where am I going wrong here?

like image 234
Program.X Avatar asked Apr 23 '15 10:04

Program.X


People also ask

Can async method have return value?

Async methods can have the following return types: Task, for an async method that performs an operation but returns no value. Task<TResult>, for an async method that returns a value. void , for an event handler.

What return types are allowed for asynchronous methods?

Async Method Return Types There are three return types that a method marked async may have: void. Task. Task< T > for some type T.

What is async return method?

Async functions always return a promise. If the return value of an async function is not explicitly a promise, it will be implicitly wrapped in a promise.


1 Answers

  • Convert your collection of Things into a collection of Task<Thing>s.
  • Then join all those tasks using Task.WhenAll and await it.
  • Awaiting the joint task will give you a 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.

like image 113
dcastro Avatar answered Dec 08 '22 10:12

dcastro