handling - throw custom exception c#
¿Cómo evitar que una excepción en un hilo de fondo termine una aplicación? (5)
Puedo conectarme a AppDomain.CurrentDomain.UnhandledException
para registrar excepciones de subprocesos en segundo plano, pero ¿cómo puedo evitar que terminen el tiempo de ejecución?
Aquí hay una gran publicación en el blog sobre este problema: Manejo de "Excepciones no controladas" en .NET 2.0
OMI sería correcto manejar las excepciones en los hilos de fondo de forma manual 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));
}
Del excelente artículo de threading Joe Albahari:
.NET Framework proporciona un evento de nivel inferior para el manejo de excepciones globales: AppDomain.UnhandledException. Este evento se dispara 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, si bien ofrece un buen mecanismo de último recurso para registrar excepciones no procesadas, no proporciona ningún medio para evitar que la aplicación se cierre, y no hay forma de suprimir el diálogo de excepciones no controladas de .NET.
En las aplicaciones de producción, se requiere el manejo de excepciones explícito en todos los métodos de entrada de subprocesos. Uno puede cortar el trabajo mediante el uso de un contenedor o clase auxiliar para realizar el trabajo, como BackgroundWorker (discutido en la Parte 3).
En primer lugar, deberías tratar de evitar que se generen excepciones, y no se manejen, en un hilo 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.
De regreso a .Net 1.1, una excepción no controlada en un hilo de fondo simplemente sería arrojada a ninguna parte y el hilo principal con mucho gusto continuaría. Y eso podría tener repercusiones desagradables. Entonces en .Net 2.0 este comportamiento ha cambiado.
Ahora, una excepción no controlada arrojada 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.
Como esto puede ser un inconveniente (cuando no sabes qué se ejecutará en el hilo y no estás del todo seguro de que esté debidamente protegido, y tu hilo principal debe ser resistente), hay una solución alternativa. Está pensado como una configuración heredada (es decir, se recomienda encarecidamente que se asegure de no tener hilos sueltos), pero puede forzar el comportamiento anterior de esta manera:
Simplemente agregue esta configuración a su servicio / aplicación / cualquier archivo de configuración:
<configuration>
<runtime>
<!-- the following setting prevents the host from closing when an unhandled exception is thrown -->
<legacyUnhandledExceptionPolicy enabled="1" />
</runtime>
</configuration>
Sin embargo, parece que no funciona con ASP.NET.
Para obtener más información (y una gran advertencia de que esta configuración no se admite en las próximas versiones de la CLR), consulte http://msdn.microsoft.com/en-us/library/ms228965.aspx
Mantener la respuesta corta, sí, puede evitar que el tiempo de ejecución termine.
Aquí hay una demostración de la solución alternativa:
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();
}
}
Básicamente, simplemente no dejaste que el tiempo de ejecución muestre el diálogo "... el programa ha dejado de funcionar".
En caso de que necesite registrar la excepción y salir silenciosamente , puede llamar a Process.GetCurrentProcess().Kill();
AppDomain.CurrentDomain.UnhandledException += (sender, e2) =>
{
Thread.CurrentThread.Join();
};
Pero tenga cuidado, este código congelará toda la memoria de la pila del hilo y del objeto gestionado del hilo. Sin embargo, si su aplicación está en un estado determinado (es posible que haya lanzado la excepción de limitación de definición de funciones o OperationStopWithUserMessageException) y no está desarrollando la aplicación las 24 horas del día, los 7 días de la semana, este truco funcionará.
Finalmente, creo que MS debería permitir a los desarrolladores anular la lógica de las excepciones no manejadas desde la parte superior de la pila.