2008-10-09 18 views

Respuesta

35

En primer lugar, debe intentar que no se generen excepciones, y no se manejen, en una cadena de fondo. Si controlas la forma en que se ejecuta tu delegado, encapsulalo en un bloque try catch y encuentra la forma de pasar la información de excepción a tu hilo principal (usando EndInvoke si llamaste explícitamente a BeginInvoke, o actualizando algún estado compartido en alguna parte).

Ignorar una excepción no controlada puede ser peligroso. Si tiene una excepción real no manejable (OutOfMemoryException viene a la mente), no hay mucho que pueda hacer de todos modos y su proceso está básicamente condenado.

Volver a .Net 1.1, una excepción no controlada en un hilo de fondo simplemente se arrojaría a la nada y el hilo principal con mucho gusto seguiría. Y eso podría tener repercusiones desagradables. Entonces en .Net 2.0 este comportamiento ha cambiado.

Ahora, una excepción no controlada lanzada en un hilo que no es el hilo principal terminará el proceso. Es posible que se lo notifique (al suscribirse al evento en AppDomain), pero el proceso morirá de todos modos.

Dado que esto puede ser un inconveniente (cuando no sabe qué se ejecutará en el hilo y no está absolutamente seguro de que esté correctamente protegido, y su hilo principal debe ser resistente), hay una solución. Está pensado como una configuración heredada (es decir, se recomienda encarecidamente que se asegure de no tener subprocesos) pero puede forzar el comportamiento anterior de esta manera:

Simplemente agregue esta configuración a su archivo de configuración de servicio/aplicación/lo que sea :

<configuration> 
    <runtime> 
    <!-- the following setting prevents the host from closing when an unhandled exception is thrown --> 
    <legacyUnhandledExceptionPolicy enabled="1" /> 
    </runtime> 
</configuration> 

Parece que no funciona con ASP.NET.

Para obtener más información (y una gran advertencia de que este ajuste no se admita en futuras versiones del CLR) ver http://msdn.microsoft.com/en-us/library/ms228965.aspx

+0

teniendo intentar ... las capturas por todo el lugar apestan. Solo querría una en la ubicación no controlada Y no querría que mi aplicación muriera porque un simple nullpointer simplemente sucedía cuando un usuario hacía clic en "feature X" y les dijimos que usen la otra función del botón X que estaba funcionando. .no apaga la aplicación cada vez, lo que molesta al usuario tanto como el error original molestaba. (iniciar una aplicación lleva tiempo, por lo que agrega molestia a los usuarios) –

+0

Tengo problemas con una biblioteca externa con errores que erráticamente bloquea la aplicación con una 'ArgumentNullException' (interna). Me gustaría habilitar 'legacyUnhandledExceptionPolicy' solo para esa biblioteca. Se puede hacer esto? – chris

7

De threading excelente artículo de Joe Albahari:

.NET Framework proporciona un evento de menor nivel mundial para el manejo excepción : AppDomain.UnhandledException. Este evento se desencadena cuando hay una excepción no controlada en cualquier subproceso y en cualquier tipo de aplicación (con o sin una interfaz de usuario ). Sin embargo, aunque ofrece un buen mecanismo de último recurso para el registro de excepciones no atrapado, que proporciona ningún medio de prevención de la aplicación se apague - y ninguna manera de suprimir el diálogo de excepción no controlada .NET .

En las aplicaciones de producción, se requiere el manejo de excepciones explícito en todos los métodos de entrada de subprocesos . Se puede cortar el trabajo mediante el uso de una clase contenedora o auxiliar para realizar el trabajo, como BackgroundWorker (explicado en la Parte 3).

1

Aquí es un gran post sobre este problema: Handling "Unhandled Exceptions" in .NET 2.0

OMI que lo haría Tenga razón al manejar las excepciones en los subprocesos de fondo manualmente y volver a lanzarlos a través de la devolución de llamada si es necesario.

delegate void ExceptionCallback(Exception ex); 

void MyExceptionCallback(Exception ex) 
{ 
    throw ex; // Handle/re-throw if necessary 
} 

void BackgroundThreadProc(Object obj) 
{ 
    try 
    { 
    throw new Exception(); 
    } 
    catch (Exception ex) 
    { 
    this.BeginInvoke(new ExceptionCallback(MyExceptionCallback), ex); 
    } 
} 

private void Test() 
{ 
    ThreadPool.QueueUserWorkItem(new WaitCallback(BackgroundThreadProc)); 
} 
4

En pocas palabras, sí, puede evitar que el tiempo de ejecución finalice.

Aquí es una demostración de la solución:

class Program 
{ 
    void Run() 
    { 
     AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); 

     Console.WriteLine("Press enter to exit."); 

     do 
     { 
      (new Thread(delegate() 
      { 
       throw new ArgumentException("ha-ha"); 
      })).Start(); 

     } while (Console.ReadLine().Trim().ToLowerInvariant() == "x"); 


     Console.WriteLine("last good-bye"); 
    } 

    int r = 0; 

    void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 
    { 
     Interlocked.Increment(ref r); 
     Console.WriteLine("handled. {0}", r); 
     Console.WriteLine("Terminating " + e.IsTerminating.ToString()); 

     Thread.CurrentThread.IsBackground = true; 
     Thread.CurrentThread.Name = "Dead thread";    

     while (true) 
      Thread.Sleep(TimeSpan.FromHours(1)); 
     //Process.GetCurrentProcess().Kill(); 
    } 

    static void Main(string[] args) 
    { 
     Console.WriteLine("..."); 
     (new Program()).Run(); 
    } 
} 

Esencialmente, usted simplemente no deja que el tiempo de ejecución para mostrar el cuadro de diálogo "... programa ha dejado de funcionar".

En caso de que necesite registrar la excepción y silencio salida, puede llamar Process.GetCurrentProcess().Kill();

+0

ick. ahora mi hilo está colgado y atorado para siempre y cada vez cuelgan más hilos. Prefiero tener una forma como Java de continuar avanzando ... tuvimos algunas excepciones que no fueron desastrosas en Java y la aplicación siguió funcionando y les dijimos a los usuarios que simplemente evitaran los pasos del caso de la esquina de 1,2,3. Esto parece malo que C# no lo soporte bien. –

+0

Sí, este es un truco sucio, por cierto. Se supone que los hilos manejan todas las excepciones. –

0
AppDomain.CurrentDomain.UnhandledException += (sender, e2) => 
    { 
     Thread.CurrentThread.Join(); 
    }; 

Pero cuidado, este código se congelará toda la memoria de pila de la rosca y el mismo objeto administrado de hilo. Sin embargo, si su aplicación está en un estado determinado (puede lanzar la excepción LimitedDemoFunctionalityException u OperationStopWithUserMessageException) y no está desarrollando la aplicación 24/7 este truco funcionará.

Finalmente, creo que MS debería permitir a los desarrolladores anular la lógica de las excepciones no controladas desde la parte superior de la pila.

Cuestiones relacionadas