Я хочу, чтобы Задание обрабатывало любые возникающие исключения, но мне трудно помешать им добраться до родителя. - PullRequest
8 голосов
/ 19 июля 2010

Я работаю над веб-хуком в .NET 4.0, который будет запускать лямбду асинхронно, а затем отправлять результат на заданный URI, когда он будет завершен.

У меня это работает, но теперь я хочу, чтобы Задача обрабатывала любые сгенерированные исключения, и мне трудно помешать им достичь родителя.

Вот часть моего кода:

private readonly Func<T> _startTask;
private readonly string _responseUri;

public Task<T> Begin()
{
    var task = new Task<T>(_startTask);
    task.ContinueWith<T>(End);
    task.Start();
    return task;
}

private T End(Task<T> task)
{
    if (task.IsFaulted)
    {
        return HandleException(task);
    }

    var result = task.Result;
    WebHookResponse.Respond(result, _responseUri);
    return result;
}

private T HandleException(Task<T> task)
{
    WebHookResponse.HandleException(task.Exception.InnerException, _responseUri);
    return null;
}

Альтернативная версия, которую я пробовал, дважды вызывает ContinueWith(), чтобы зарегистрировать одно продолжение для запуска OnlyOnRanToCompletion и одно для запуска OnlyOnFaulted. (Я не уверен, что вызов ContinueWith() дважды - это правильно.):

public Task<T> Begin()
{
    var task = new Task<T>(_startTask);
    task.ContinueWith<T>(End, TaskContinuationOptions.OnlyOnRanToCompletion);
    task.ContinueWith<T>(HandleException, TaskContinuationOptions.OnlyOnFaulted);
    task.Start();
    return task;
}

private T End(Task<T> task)
{
    var result = task.Result;
    WebHookResponse.Respond(result, _responseUri);
    return result;
}

private T HandleException(Task<T> task)
{
    WebHookResponse.HandleException(task.Exception.InnerException, _responseUri);
    return null;
}

Так что, в принципе, я хочу, чтобы каждая Задача обрабатывала свои собственные исключения через функцию продолжения. В нынешнем виде функция продолжения HandlException никогда не вызывается ни в одном из приведенных выше примеров.

Я вызываю исключения в тестовом примере, и я должен упомянуть, что я использую вызов Tasks.WaitAll(tasks); для массива задач, чтобы убедиться, что все задачи завершены, прежде чем делать свои утверждения, и я не уверен если этот вызов имеет значение для обработки исключений Задачами. В настоящее время WaitAll генерирует исключение AggregationException, которое объединяет исключения для каждой из задач, поскольку они не обрабатываются функцией продолжения HandleException.

Ответы [ 3 ]

3 голосов
/ 13 марта 2012

Продолжение задачи, которое наблюдает за исключением задачи, не обрабатывает исключение. Это по-прежнему происходит там, где вы ожидаете завершения задачи.

Вы сказали, что вызывали WaitAll (задачи) перед подтверждением. Держу пари, что ваше продолжение запустилось бы, если бы вы дали ему достаточно времени, но исключение в WaitAll () обычно происходит до того, как ваше продолжение запустится. Таким образом, ваши утверждения, вероятно, потерпели неудачу, прежде чем вашему продолжению была предоставлена ​​возможность завершить свою работу.

1 голос
/ 09 октября 2015

Я использую этот подход, потому что он обеспечивает хороший декларативный свободный стиль кодирования и не засоряет ваш код аспектами обработки исключений.

1 голос
/ 10 февраля 2012

Возможно, к ответу Хенка Холтермана, заказ имеет значение. То есть

var task = new Task<T>(_startTask);
task = task.ContinueWith<T>(HandleException, TaskContinuationOptions.OnlyOnFaulted);
task = task.ContinueWith<T>(End, TaskContinuationOptions.OnlyOnRanToCompletion);
task.Start();

обеспечит запуск HandleException при необходимости.

...