Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async controller action with loop

How would I go about writing an async controller action that is made up of 1 +n async calls (await)? E.g. let's pretend I need to retrieve the object Foo first and it has a variable number of Bars identifier and I need to fetch all those entities (for the sake of this question, there is no fetchBarsByFooId. Would I use Task.WaitAll or maybe Parallel.For?

public async Task<ActionResult> Bars(int id) {
    Foo foo = await this.FooProvider.GetFooAsync(id);
    var bars = new ConcurrentQueue<Bar>();

    // Sub-optimal version
    foreach (int barId in foo.BarIDs) {
        Bar bar = this.BarProvider.GetBar(barId);
        bars.Enqueue(bar)
    }

    // Fetch each bar asynchronously and pass them to the view.
    ....

    return View(bars.ToArray());
}
like image 898
Oli Avatar asked Mar 10 '26 08:03

Oli


1 Answers

Well, the first thing to work out is whether you actually want parallelism, or just asynchrony. Just asynchrony is simple:

var bars = new List<Bar>();
foreach (var id in foo.Bars)
{
    bars.Add(await BarProvider.GetBarAsync(id));
}
return View(bars);

For parallelism, you could use Task.WhenAll:

var tasks = foo.Bars.Select(id => BarProvider.GetBarAsync(id));
var bars = await Task.WhenAll(tasks);
return View(bars);

(I realize this is shorter code than the non-parallel version - but it's more conceptually tricky.)

You should not use Parallel.For or Task.WaitAll as both of those are blocking calls - whereas Task.WhenAll returns you a task which will complete when all the subtasks have completed.

like image 66
Jon Skeet Avatar answered Mar 12 '26 21:03

Jon Skeet



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!