Исключение (исключения) задачи не наблюдалось ни при ожидании задачи, ни при доступе к ее свойству Exception. В результате необнаруженное исключение было

Что это значит и как его решить?

Я использую задачи TPL.

Вся ошибка

Исключение (исключения) задачи не наблюдалось ни при ожидании задачи, ни при доступе к ее свойству Exception. В результате незаметное исключение было восстановлено потоком финализатора.

в System.Threading.Tasks.TaskExceptionHolder.Finalize()

mscorlib

Ответ 1

Если вы создаете задачу, и вы никогда не вызываете task.Wait() или не пытаетесь получить результат Task<T>, когда сбор сборщика мусора собирается, он будет разорвать ваше приложение во время финализации. Подробнее см. на странице MSDN в Обработка исключений в TPL.

Лучший вариант здесь - "обработать" исключение. Это можно сделать с помощью продолжения - вы можете приложить продолжение к задаче и выполнить log/swallow/etc исключение. Это обеспечивает чистый способ регистрации исключений задач и может быть записан как простой метод расширения, то есть:

public static void LogExceptions(this Task task)
{
    task.ContinueWith( t =>
    {
         var aggException = t.Exception.Flatten();
         foreach(var exception in aggException.InnerExceptions)
             LogException(exception);
    }, 
    TaskContinuationOptions.OnlyOnFaulted);
}

С помощью вышеизложенного вы можете не допустить, чтобы любая задача отрывала приложение и регистрировала его, используя:

Task.Factory.StartNew( () => 
   { 
       // Do your work...
   }).LogExceptions();

Кроме того, вы можете подписаться на TaskScheduler.UnobservedTaskException и обрабатывать его там.

Ответ 2

Конечно; это означает, что Task получил финализацию после того, как его оставили на сборку мусора, но сама задача потерпела неудачу. Есть два исправления:

  • обрабатывать задачи сбой напрямую (используйте ContinueWith(...) для подписки и проверьте .IsFaulted и .Exception на Task в параметре)
  • обрабатывать событие TaskScheduler.UnobservedTaskException и отмечать его наблюдаемым (вызов e.SetObserved() после регистрации ошибки)

Ответ 3

Попробуйте следующее:

public static void ThrowFirstExceptionIfHappens(this Task task)
{
    task.ContinueWith(t =>
    {
        var aggException = t.Exception.Flatten();
        foreach (var exception in aggException.InnerExceptions)
        {
            throw exception; // throw only first, search for solution
        }
    },
    TaskContinuationOptions.OnlyOnFaulted); // not valid for multi task continuations
}

public static Task CreateHandledTask(Action action) 
{
    Task tsk = Task.Factory.StartNew(action);
    tsk.ThrowFirstExceptionIfHappens();
    return tsk;
}