Необработанные исключения в BackgroundWorker


У меня есть небольшое приложение WinForms, которое использует объект BackgroundWorker для выполнения длительной операции.

фоновая операция вызывает случайные исключения, как правило, когда у кого-то есть открытый файл, который воссоздается.

независимо от того, выполняется ли код из IDE или нет.net, появляется диалоговое окно с сообщением об ошибке, информирующее пользователя о том, что произошло необработанное исключение. Компиляция кода с использованием конфигурации выпуска не изменяет этого любой.

по данным MSDN:

Если операция вызывает исключение, которое ваш код не обрабатывает, BackgroundWorker ловит исключение и передает его в обработчик событий RunWorkerCompleted, где оно предоставляется как свойство Error системы.ComponentModel..::.RunWorkerCompletedEventArgs. Если вы работаете под отладчиком Visual Studio, отладчик сломается в точке в обработчике событий DoWork, где необработанный возникло исключение.

Я ожидаю, что эти исключения будут брошены время от времени и хотел бы обрабатывать их в RunWorkerCompleted событии, а не в DoWork. Мой код работает правильно, и ошибка обрабатывается правильно в событии RunWorkerCompleted, но я не могу понять, как остановить диалоговое окно ошибки .NET, жалующееся на "необработанное исключение".

разве BackgroundWorker не должен поймать эту ошибку автоматически? Разве не об этом говорится в документации MSDN? Что мне нужно сделать, чтобы сообщить .NET, что эта ошибка и обрабатывается, все еще позволяя исключению продвигаться в свойство Error RunWorkerCompletedEventArgs?

5 64

5 ответов:

то, что вы описываете, не является определенным поведением BackgroundWorker. Я подозреваю, что ты делаешь что-то не так.

вот небольшой пример, который доказывает, что BackgroundWorker ест исключения в DoWork, и делает их доступными для вас в RunWorkerCompleted:

var worker = new BackgroundWorker();
worker.DoWork += (sender, e) => 
    { 
        throw new InvalidOperationException("oh shiznit!"); 
    };
worker.RunWorkerCompleted += (sender, e) =>
    {
        if(e.Error != null)
        {
            MessageBox.Show("There was an error! " + e.Error.ToString());
        }
    };
worker.RunWorkerAsync();

мои экстрасенсорные навыки отладки раскрывают мне вашу проблему: вы получаете доступ к e. результат в вашем обработчике RunWorkerCompleted - если есть ошибка e., вы должны справиться это без доступа е. результат. Например, следующий код является плохим, плохим, плохим и вызовет исключение во время выполнения:

var worker = new BackgroundWorker();
worker.DoWork += (sender, e) => 
    { 
        throw new InvalidOperationException("oh shiznit!"); 
    };
worker.RunWorkerCompleted += (sender, e) =>
    {
        // OH NOOOOOOOES! Runtime exception, you can't access e.Result if there's an
        // error. You can check for errors using e.Error.
        var result = e.Result; 
    };
worker.RunWorkerAsync();

вот правильная реализация обработчика событий RunWorkerCompleted:

private void RunWorkerCompletedHandler(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error == null)
    {
       DoSomethingWith(e.Result); // Access e.Result only if no error occurred.
    }
}

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

Я бы добавил к MSDN text:

Если операция вызывает исключение, которое ваш код не обрабатывает, BackgroundWorker ловит исключение и передает его в обработчик событий RunWorkerCompleted, где оно предоставляется как свойство Error системы.ComponentModel..::.RunWorkerCompletedEventArgs. если вы работаете под отладчиком Visual Studio, отладчик сломается в точке в обработчике событий DoWork, где необработанный возникло исключение.

... И отладчик сообщит об исключении как "~Exception was unhandled by user code"

решение: не запускайте под отладчиком, и он работает так, как ожидалось: исключение, пойманное в e.Error.

Это старый вопрос, но я нашел его, когда искал те же симптомы. Разместите это в случае, если кто-то другой найдет его по той же причине.

ответ Иуды правильный, но это не единственная причина, по которой может появиться диалоговое окно "необработанное исключение в коде пользователя". Если возникает исключение внутри конструктора в фоновом потоке это исключение немедленно вызовет диалоговое окно и не будет передано в событие RunWorkerCompleted. Если вы переместите нарушение кода вне любых конструкторов (для любого другого метода) он работает так, как ожидалось.

[Edit]

Иуда имеет большое значение. Мой пример указал на специфику обработки ошибки, но мой код фактически вызовет другое исключение, если исключение никогда не попадало в метод DoWork. Этот пример в порядке из-за того, что мы специально показываем возможности обработки ошибок BackgroundWorker. Однако если вы не проверяете параметр ошибки против null, то это может быть ваша проблема.

[/Edit]

Я не вижу те же результаты. Вы можете разместить немного кода? Вот мой код.

private void Form1_Load(object sender, EventArgs e)
{
    BackgroundWorker worker = new BackgroundWorker();
    worker.DoWork += new DoWorkEventHandler(worker_DoWork);
    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    worker.RunWorkerAsync();
}

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // Will cause another exception if an exception didn't occur.
    // We should be checking to see if e.Error is not "null".
    textBox1.Text = "Error? " + e.Error;
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    for (int i = 0; i < 10; i++)
    {
        if (i < 5)
        {
            Thread.Sleep(100);
        }
        else
        {
            throw new Exception("BOOM");
        }   
    }
}

Программа:

ошибка? Система.Исключение: BOOM at BackgroundException.Форма 1.worker_DoWork (объект отправитель, DoWorkEventArgs e) in D:\Workspaces\Sandbox\BackgroundException\BackgroundException\Form1.cs: линия 43 at Система.ComponentModel.BackgroundWorker.OnDoWork (DoWorkEventArgs д) При Система.ComponentModel.BackgroundWorker.WorkerThreadStart(Объект аргумент)

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

http://www.developerdotstar.com/community/node/671

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

Ну, ИМО ответ Иуды частично правильный. Я нашел лучший ответ здесь

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

Я надеюсь, что этот ответ помогает.