2008-11-03 26 views
72

Mi aplicación WinForms utiliza un número de objetos BackgroundWorker para recuperar información de una base de datos. Estoy usando BackgroundWorker porque permite que la IU permanezca desbloqueada durante consultas de base de datos de larga ejecución y simplifica el modelo de subprocesamiento para mí.Excepciones no controladas en BackgroundWorker

Recibo ocasionalmente DatabaseExceptions en algunos de estos subprocesos en segundo plano, y he sido testigo de al menos una de estas excepciones en un hilo de trabajo durante la depuración. Estoy bastante seguro de que estas excepciones son tiempos de espera que supongo que es razonable esperar de vez en cuando.

Mi pregunta es acerca de qué ocurre cuando se produce una excepción no controlada en uno de estos hilos del trabajador de fondo.

No creo que pueda detectar una excepción en otro hilo, pero ¿puedo esperar que se ejecute mi método WorkerCompleted? ¿Hay alguna propiedad o método del BackgroundWorker que pueda interrogar para excepciones?

Respuesta

77

Si la operación genera una excepción de que el código no maneja, la BackgroundWorker captura la excepción y lo pasa al manejador RunWorkerCompleted evento, donde se expone como la propiedad de error de System.ComponentModel.RunWorkerCompletedEventArgs. Si se ejecuta con el depurador de Visual Studio, el depurador se romperá en el punto en el controlador de eventos DoWork donde se produjo la excepción no controlada.

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.dowork.aspx

+5

Eso lo hará. Por supuesto, siempre puedes ver la excepción en tu método DoWork y reaccionar en consecuencia (recordando usar Control.Invocar si vas a actualizar la UI). Pero RunWorkerCompleted es de hecho más simple. –

+0

Estoy buscando esta solución. Mi RunWorkerCompleted no se ejecuta cuando simplemente lanzo una nueva excepción() pero aparece una excepción no controlada. atrapar en DoWork no es la verdadera respuesta. Debería haber algo mal en mi BackgroundWorker. – CallMeLaNN

+0

Acabo de pasar las últimas siete horas intentando averiguar por qué mi aplicación no se ejecutará y acaba de salir, y todo porque se produjo un error en BackgroundWorker que no se captó correctamente. +1 para ti y creo que también te mereces una cerveza :-) – EvilDr

10

Por defecto, serán capturados y almacenados por el BackgroundWorker. De MSDN:

Si la operación genera una excepción de que el código no maneja, la BackgroundWorker captura la excepción y lo pasa al controlador de eventos RunWorkerCompleted, donde se expone como la propiedad de error de System.ComponentModel.RunWorkerCompletedEventArgs . Si se ejecuta con el depurador de Visual Studio, el depurador se romperá en el punto en el controlador de eventos DoWork donde se produjo la excepción no controlada.

34

Estoy usando completamente BackgroundWorker durante años y realmente lo conozco en profundidad.

Recientemente, Mi RunWorkerCompleted no detecta el e.Error cuando simplemente Throw New Exception("Test") en DoWork. Sin embargo Excepción no controlada planteada. Capturar en DoWork no es la mejor práctica por lo tanto e.Error no tiene sentido.

Cuando intento crear nueva Form con el nuevo BackgroundWorker, e.Error en RunWorkerCompleted manejado con éxito. Debería haber algo mal en mi complicado BackgroundWorker.

Después de unos días googleando y depurando, intentando un error. He encontrado esto en mi RunWorkerCompleted:

  • Comprobar si e.Error primero, y luego e.Cancelled y por último e.Result
  • No permita que la e.Result si e.Cancelled = True.
  • no consigue los e.Result si no es e.Errornull (o Nothing) **

** Aquí es donde me olvido. Si intenta utilizar e.Result si e.Error no es null (o Nothing), se lanzará una excepción no controlada.


ACTUALIZACIÓN: En el diseño e.Result obtener la propiedad .NET para comprobar si hay e.Error primer error, si tiene, entonces van a volver a la misma excepción de DoWork. Es por eso que obtenemos excepción no controlada en RunWorkerCompleted pero en realidad la excepción proviene de DoWork.

Aquí es la mejor práctica para hacer en RunWorkerCompleted:

If e.Error IsNot Nothing Then 
    ' Handle the error here 
Else 
    If e.Cancelled Then 
    ' Tell user the process canceled here 
    Else 
    ' Tell user the process completed 
    ' and you can use e.Result only here. 
    End If 
End If 

Si desea que un objeto que se puede acceder a todos DoWork, ProgressChanged y RunWorkerCompleted, utilice la siguiente manera:

Dim ThreadInfos as Dictionary(Of BackgroundWorker, YourObjectOrStruct) 

Usted puede fácilmente acceda al ThreadInfos(sender).Field en cualquier lugar que desee.

+1

No. Puse Throw New Exception ('Prueba') en DoWork. Luego RunWorkerCompleted se activó y llamo a e.Result antes de e.Error. Esto está mal. Debido a que e.Error no es nulo (o Nothing), no podemos llamar a e.Result. Llamar a e.Result cuando e.Error IsNot Nothing O e.Cancelled = True arrojará una excepción no controlada en RunWorkerCompleted. Por lo tanto, verifique e.Error y e.Cancelado antes de llamar a e.Result. – CallMeLaNN

+0

Al intentar acceder a E.Result en mi eventhandler completo estaba lanzando una TargetInvocationException cuando mi DoWork cometió un error. ¡Ahora compruebo si el error es nulo o si se canceló antes de acceder al resultado y mi código está solucionado! Te lo digo porque tu explicación me ayudó a corregir mi código de producción. ¡Muchas gracias! – jlafay

+0

@CallMeLaNN Excelente información. Estaba haciendo el mismo error. –

4

Como ya se señaló:

Si la operación genera una excepción que su código no maneja, la BackgroundWorker captura la excepción y lo pasa al controlador de eventos RunWorkerCompleted, donde se expone como la propiedad Error de System.ComponentModel.RunWorkerCompletedEventArgs.

Esto es importante siempre que esté interactuando con el hilo original. Por ejemplo, si desea que el resultado de su excepción se escriba en algún tipo de etiqueta en su formulario, es cuando no debe detectar la excepción en DoWork del BackgroundWorker, sino que debe manejar e.Error desde RunWorkerCompletedEventArgs.

Si analiza el código de BackgroundWorker con reflector, puede ver que todo se maneja bastante sencillo: Su DoWork se ejecuta en un bloque try-catch, y la excepción acaba de pasar a RunWorkerCompleted. Cuál es la razón por la que no estoy de acuerdo con el método "preferido" de capturar siempre todas sus excepciones en el evento DoWork.

En resumen, para responder a la pregunta original:

- se puede contar con su RunWorkerCompleted ser despedido siempre.

Use e.Error de RunWorkerCompletado para buscar excepciones en el otro hilo.

3

Esto funcionará solo sin el depurador conectado, cuando se ejecuta desde Visual Studio, el depurador detectará la excepción sin manos en el método DoWork y interrumpirá la ejecución; sin embargo, puede hacer clic en continuar y se llegará a RunWorkerCompleted y estará capaz de leer excepciones a través del campo e.Error.

Cuestiones relacionadas