Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieving what did work when Task.WhenAll throws exception

Consider

string[] pages;
Task [] asyncOps = 
    (from url in urls select DownloadStringAsync(url)).ToArray();
try
{
    pages = await Task.WhenAll(asyncOps);
    ...
}
catch(Exception exc)
{
    foreach(Task<string> faulted in asyncOps.Where(t => t.IsFaulted))
    {
        … // work with faulted and faulted.Exception
    }
}

from https://msdn.microsoft.com/en-us/library/hh873173%28v=vs.110%29.aspx. How can I retrieve the pages that DID work?

Or better, how can I keep going and compute the rest of the pages?

like image 641
tofutim Avatar asked Feb 13 '26 00:02

tofutim


2 Answers

Instead of doing all the downloads and then handling each success/error separately, I think it's much cleaner if you define a separate "download and handle error" operation:

Task [] asyncOps = 
    (from url in urls select DownloadStringWithErrorCheckingAsync(url)).ToArray();
string[] pages = await Task.WhenAll(asyncOps);
var successfulPages = pages.Where(x => x != null);

...

private static Task<string> DownloadStringWithErrorCheckingAsync(string url)
{
  try
  {
    return await DownloadStringAsync(url);
  }
  catch(Exception exc)
  {
    ... // work with exc
    return null;
  }
}
like image 115
Stephen Cleary Avatar answered Feb 15 '26 14:02

Stephen Cleary


I've same problem. I need to start several task, wait for each to terminate and then, process all task Status/Exception/Result.

I can't use Stephen's solution because final processings are not independent from each other. It's some kind of: if task1 is Ok, I will try to take result of task2 and if not, I will take task3 result. I need each response to infer my behavior.

Task[] toWait = new Task[]{...};

await Task.WhenAll(toWait).ContinueWith((t) => {t?.Exception?.Handle((exc)=>true);}, ct);

I don't await result of WhenAll but result of ContinueWith whose action only silently handle exception.

It's not very elegant but we can hide it with a method like this one:

public static Task WhenAllNoThrow(this Task[] toWait, CancellationToken token)
{
    return TaskEx.WhenAll(toWait).ContinueWith((t) => { t?.Exception?.Handle((exc) => true); }, token);
}

EDIT: Added null-conditional Operators ?.

like image 43
MuiBienCarlota Avatar answered Feb 15 '26 12:02

MuiBienCarlota



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!