Ошибка при использовании Task.Factory

Я использую следующие

Task.Factory.StartNew(() => DoPrintConfigPage(serial));

то функция, которую я вызываю, выглядит так:

private void DoPrintConfigPage(string serial) 
{ 
    //do printing work 
}

Моя проблема заключается в том, что исключение вызывается внутри потока и не обрабатывается.

Я попробовал обернуть его в try catch

try
{
    Task.Factory.StartNew(() => DoPrintConfigPage(serial));
}
catch (Exception ex) { }

но он все еще не поймает ошибку и, таким образом, сбой приложения.

Как я могу поймать исключения в основном потоке, чтобы я мог их обработать?

Update

Я внес изменения, рекомендованные ниже, и все же он говорит, что исключение необработанное

var task =  Task.Factory.StartNew(() => DoPrintConfigPage(serial))
                               .ContinueWith(tsk =>
                               {
                                  MessageBox.Show("something broke");
                               },TaskContinuationOptions.OnlyOnFaulted);

то в моем DoConfigPage я добавил еще одну попытку.

В этом уловке теперь происходит сбой и говорят, что исключенное исключение было необработанным, что мне не хватает?

private void DoPrintConfigPage(string serial)
{
    try
    {
        //call the print function
    }
    catch (Exception ex)
    {
        throw ex;   //it is crashing here and saying it is unhandled
    }
}

Я также пробовал то, что предложил Эрик Дж. с теми же результатами

var task = Task.Factory.StartNew(() => DoPrintConfigPage(serial));

try
{
    task.Wait();                  
}
catch (AggregateException ex) { MessageBox.Show("something broke"); }

Ответ 1

В качестве альтернативы вы можете связать создание своей задачи и добавить ContinueWith:

var job = Task.Factory
    .StartNew(...)
    .ContinueWith(tsk => 
         {
              // check tsk for exception and handle
         });

EDIT: этот фрагмент, когда он запускается, выдает мне окно сообщений:

void Main()
{
    var serial = "some serial";
    var task =  Task.Factory
        .StartNew(() => DoPrintConfigPage(serial))
        .ContinueWith(tsk =>
        {
            MessageBox.Show("something broke");
            var flattened = tsk.Exception.Flatten();

            // NOTE: Don't actually handle exceptions this way, m'kay?
            flattened.Handle(ex => { MessageBox.Show("Error:" + ex.Message); return true;});
        },TaskContinuationOptions.OnlyOnFaulted);

}

public void DoPrintConfigPage(string serial)
{
    throw new Exception("BOOM!");
}

Ответ 2

Ваш блок try завершается сразу после запуска новой задачи, потому что этот метод продолжает работать.

Вместо этого вы можете поймать Exception как AggregateException, где вы ожидаете завершения задачи (или нескольких задач):

var task1 = Task.Factory.StartNew(() =>
{
    throw new MyCustomException("I'm bad, but not too bad!");
});

try
{
    task1.Wait();
}
catch (AggregateException ae)
{
    // Assume we know what going on with this particular exception. 
    // Rethrow anything else. AggregateException.Handle provides 
    // another way to express this. See later example. 
    foreach (var e in ae.InnerExceptions)
    {
        if (e is MyCustomException)
        {
            Console.WriteLine(e.Message);
        }
        else
        {
            throw;
        }
    }

}

http://msdn.microsoft.com/en-us/library/dd997415.aspx

Ответ 3

Вы также должны знать о System.Threading.Tasks.TaskScheduler.UnobservedTaskException.

Если вы занимаетесь созданием экземпляров "fire and forget" Task, вы захотите подписаться на это событие в начале вашей программы.

Ответ 4

Если вы не ожидаете своей задачи, я думаю, что самое легкое решение найдено в Task.Exception:

Получает исключение AggregateException, которое вызвало преждевременное завершение задачи. Если задание выполнено успешно или еще не исключения, это вернет null.

Я использую что-то вроде этого:

Task.Factory.StartNew(() => DoStuffHere())
    .ContinueWith(task =>
    {
        if (task.Exception != null)
            Log("log all the exceptions!");
    });

Ответ 5

Возможно, вы пытаетесь поймать Corrupted State Exception. Так как приложения .NET 4 не могут поймать такие исключения по умолчанию. Вы можете попытаться добавить запись legacyCorruptedState­­ExceptionsPolicy=true в файл конфигурации, как указано в статье MSDN, приведенной выше.