Необработанные исключения в BackgroundWorker
У меня есть небольшое приложение WinForms, которое использует объект BackgroundWorker для выполнения длительной операции.
фоновая операция вызывает случайные исключения, как правило, когда у кого-то есть открытый файл, который воссоздается.
независимо от того, выполняется ли код из IDE или нет.net появляется диалоговое окно с ошибкой, информирующее пользователя о том, что произошло необработанное исключение. Компиляция кода с использованием конфигурации Release не меняет этого любой.
по данным MSDN:
Если операция вызывает исключение, которое не обрабатывается кодом, BackgroundWorker ловит исключение и передает его в обработчик событий RunWorkerCompleted, где оно предоставляется как свойство Error системы.ComponentModel..::.RunWorkerCompletedEventArgs. Если вы работаете под отладчиком Visual Studio, отладчик сломается в точке обработчика событий DoWork, где необработанный было сделано исключение.
Я ожидаю, что эти исключения будут время от времени выбрасываться и хотели бы обрабатывать их в событии RunWorkerCompleted, а не в DoWork. Мой код работает правильно, и ошибка обрабатывается правильно в событии RunWorkerCompleted, но я не могу понять, как остановить диалоговое окно ошибки .NET, жалующееся на "необработанное исключение".
разве BackgroundWorker не должен поймать эту ошибку автомагически? Разве это не то, что говорится в документации MSDN? Что мне нужно сделать, чтобы сообщить .NET, что эта ошибка и обрабатывается, все еще позволяя исключению продвигаться в свойство Error RunWorkerCompletedEventArgs?
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.Ошибка, вы должны обработать это без доступа к 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:
Если операция вызывает исключение, которое не обрабатывается кодом, BackgroundWorker ловит исключение и передает его в обработчик событий RunWorkerCompleted, где оно предоставляется как свойство Error системы.ComponentModel..::.RunWorkerCompletedEventArgs. если вы работаете под отладчиком Visual Studio, отладчик сломается в точке обработчика событий DoWork, где необработанный было сделано исключение.
... И отладчик сообщит об исключении как "~Exception был необработан кодом пользователя"
решение: не запускайте под отладчиком, и он работает так, как ожидалось: исключение, пойманное в e.Ошибка.
Это старый вопрос, но я нашел его, когда гуглил те же симптомы. Публикация этого в случае, если кто-то другой найдет его по той же причине.
ответ Иуды правильный, но это не единственная причина, по которой может появиться диалоговое окно "необработанное исключение в коде пользователя". Если создается исключение внутри конструктора в фоновом потоке это исключение немедленно вызовет диалоговое окно и не будет передано событию 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.Форма form1.worker_DoWork (объект отправитель, DoWorkEventArgs e) в D:\Workspaces\Sandbox\BackgroundException\BackgroundException\Form1.cs: линия 43 at Система.ComponentModel.BackgroundWorker.OnDoWork (DoWorkEventArgs e) at Система.ComponentModel.BackgroundWorker.WorkerThreadStart(Объект аргумент)
интересная статья, похожая на ваш вопрос. В нем есть раздел об обработке исключений.
У меня была та же проблема, и я уже применял ответ Иуды, прежде чем нашел эту тему после некоторого гугления.
Ну, ИМО ответ Иуды частично правильный. Я нашел лучший ответ здесь
отладчик делает работу хорошо, если вы запускаете приложение в" реальных условиях", RunWorkerCompleted имеет дело с исключением, как и ожидалось, и поведение приложения также является ожидаемым.
Я надеюсь, что этот ответ помогает.