I'd like to execute multiple async tasks sequentially.
foreach (var msg in messages)
{
await smtp.SendAsync(msg);
}
However, if one of the tasks fails, I'd like the rest of them to continue. And throw one exception at the end.
Think of it like .WhenAll()
that executes all the tasks and throws an AggregateException
at the end, if any of the tasks fails. However, I cannot find any sequential alternative.
I studied the docs and googled and stackoverflowed for a solution, and I found no built-in way to do this. I think the only way is to handle exceptions manually.
Something like this
var exceptions = new List<Exception>();
foreach (var msg in messages)
{
try
{
await smtp.SendAsync(msg).ConfigureAwait(false);
}
catch (Exception ex)
{
exceptions.Add(ex);
}
}
if (exceptions.Count > 0)
{
throw new AggregateException(exceptions);
}
Questions:
.ContinueWith
calls and returning the resulting "chain-task" instead is considered a better practice? (thus eliding await/async and prevent unnecessary state-machine building)AggregateException
here or this is bad practice?Is there a .NET built-in solution I'm missing?
No. This is an unusual need, so there's nothing built-in. When doing sequential operations, it's far more common to want to stop on the first exception.
If not, is this the right way?
Yes. You can use AggregateException
if that's the semantics you want. You should prefer await
over ContinueWith
.
You may also want to consider a railway programming pattern. There isn't anything like a Try
/Error
/Exceptional
monad in the BCL but there are several libraries out there to fill that gap