Normalmente, cuando hacemos una aplicación de escritorio o servicio de Windows, intentamos, mediante try – catch de los métodos principales, evitar fallos catastróficos. Pero lo que se suele desconocer es que hay una última barrera de defensa en esta propiedad llamada UnhandledException de nuestro app domain.
En este ejemplo estoy blindado la ejecución de un servicio. Si algo falla que no esté controlado, antes de que se pare el servicio, nuestro código del segundo método se ejecutará sí o sí:
1: static void Main()
2: {
3: ServiceBase[] ServicesToRun;
4:
5: ServicesToRun = new ServiceBase[] { new BatcherService() };
6: AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
7: ServiceBase.Run(ServicesToRun);
8: }
9:
10: static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
11: {
12: ...
13: }
Ideal para esos logs de ultima hora que nos pueden servir para ver por qué realmente ha fallado. En el argumento e tenemos toda la información de la excepción tal como vemos en esta captura de la ayuda contextual.
Esto también sirve en aplicaciones WPF, Winforms etc… Espero que a alguien le sea útil.
Nota: Es conveniente que el código que metamos aquí sea ultra ligero para evitar problemas como matar el proceso a mano porque el servidor sql encargado de guardar los logs da time – out por ejemplo 😉
Update: Si queremos la aplicación termine evitando las molestas ventanas de error, debemos usar el método Enviroment.Exit()
1: static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
2: {
3: try
4: {
5: Exception ex = (Exception)e.ExceptionObject;
6: // logeamos
7: }
8: finally
9: {
10: Environment.Exit(…);
11: }
12: }
Con ello, terminaremos la ejecución, dicho de forma rápida, antes de que la excepción llegue hasta el S.O y saqué dichas ventanas.