Страницы

Поиск по вопросам

четверг, 23 мая 2019 г.

Почему исключения в асинхронном коде считаются необработанными?

Есть код скачивания файлов, на нижнем уровне есть простой цикл с ограничением, чтобы сделать несколько попыток скачивания, выглядит упрощенно вот так:
private static bool Failed = false;
static void Main(string[] args) { TaskScheduler.UnobservedTaskException += (o, a) => { throw a.Exception; }; ChapterDownload().Wait(); }
public static async Task ChapterDownload() { try { var pages = Enumerable.Range(0, 20); var pTasks = pages.Select(page => { return PageDownload() .ContinueWith(t => Console.WriteLine("{0}{1}", t.Status, t.IsFaulted)); }); await Task.WhenAll(pTasks.ToArray()); } catch (Exception ex) { // } }
public static async Task PageDownload() { if (Failed) throw new Exception("boom");
try { // var file = await new WebClient().DownloadDataTaskAsync(new Uri(@"http://example.com")); var file = await DownloadFile(new Uri(@"http://example.com")); if (file != null) throw new Exception("Restart download, downloaded file is corrupted"); } catch (Exception ex) { Failed = true; await PageDownload(); } }
public static async Task DownloadFile(Uri uri) { byte[] result; WebResponse response; var request = WebRequest.Create(uri);
try { response = await request.GetResponseAsync(); using (var memory = new MemoryStream()) { await response.GetResponseStream().CopyToAsync(memory); result = memory.ToArray(); } } catch (System.Exception ex) { return null; } if (response.ContentLength == result.LongLength) return result; return null; }
Проблема в чём - в текущем виде, происходит UnobservedTaskException, с текстовкой boom, т.е. явно моё. При этом, стоит мне заменить скачивание с самопала на webclient - UnobservedTaskException больше не возникает. В чём разница?


Ответ

Чтобы исключения задачи (Task) считались обработанными и не вызывали событие TaskScheduler.UnobservedTaskException необходимо их перевыбросить, например t.Result, t.Wait() или t.GetAwaiter().GetResult(), или просмотреть, обратившись с свойству Exception: t.Exception
В Вашем коде проблема возникает потому, что вы ждёте завершение не самих исходных задач, а их продолжений. В то время как продолжения не делают ничего, чтобы обработать исключения исходных задач. В результате исключения, возникшие в исходных задачах, остаются необработанными.

Комментариев нет:

Отправить комментарий