Uno de los grandes retos a la hora de abordar el desarrollo de una aplicación software es la gestión de los errores que puedan producirse durante su explotación o incluso durante la fase de desarrollo.
Podemos diferenciar varios tipos de errores:
- Errores sintácticos de programación. Estos son detectados por el compilador como situaciones que violan las reglas de implementación del lenguaje que estemos utilizando.
- Errores conceptuales de programación. Errores cometidos en la definición de algoritmos que llevan a situaciones no previstas.
- Errores en tiempo de ejecución. Derivados de los errores conceptuales, son los que nacen de resultados no previstos.
- Errores de planificación. Suceden cuando se pone poco empeño durante la fase de análisis y definición de un proyecto, y es especialmente visible en proyectos web, donde (generalmente) el número de archivos de código es mayor que en una aplicación de escritorio y son más dificiles de depurar.
Por suerte, hoy en día cualquier lenguaje que utilicemos cuenta con las herramientas necesarias para poder detectar los errores de los puntos 1, 2 y 3.
El más clásico es, por supuesto, la estructura try. Un ejemplo en C#:
try
{ /* Código que está siendo probado */ }
catch (Exception ex)
{ /* Código ejecutado si se produce una excepción */ }
Ahora bien, cuando estamos trabajando en una aplicación web con ASP.NET 2.0, puede que queramos realizar una gestión de errores a nivel de aplicación sin necesidad de tener que controlar cada zona del código mediante estructuras de control de excepciones.
Aquí voy a presentar el modo que yo prefiero utilizar, y que bajo mi experiencia, es el más cómodo y útil.
Para capturar los errores que se produzcan dentro de nuestr apalicación, utilizaremos el fichero Global.asax, que si no lo teneis en vuestro proyecto, podeis añadirlo en el propio directorio raíz. En él, si no lo tenemos ya, añadiremos una función de la siguiente forma:
void Application_Error(object sender, EventArgs e) { }
Cada vez que se produce una excepción no controlada dentro de nuestra aplicación web se llama a este evento de manera automática. Hay que tener en cuenta que si bien de esta manera capturamos el momento en que se produce un error, no tenemos una manera directa de acceder a la información del mismo, por lo que usaremos esta otra secuencia para recoger el objeto de excepción:
Exception ex = Server.GetLastError().GetBaseException();
Como podeis ver, ahora ya podemos acceder a toda la información que nos trae el objeto de excepción en su instancia, que hemos llamado ex.
Ahora podemos tomar varios caminos:
- Mostrar un mensaje de error al usuario.
- Genérico: configurable desde el fichero web.config, como veremos a continuación.
- Detallado con el error: no es recomendable, pero podemos imprimir en pantalla los datos del error (procedencia, mensaje, seguimiento de pila de llamadas…)
- Registrar el error en Windows.
- Enviar un correo electrónico al administrador.
Primero veamos el caso 1. Para poder activar una página genérica donde acudan los navegadores de nuestros usuarios cuando se produzca un error, modificaremos una serie de parámetros en el fichero web.config, en concreto los referentes a la etiqueta customErrors:
<customErrors mode=”RemoteOnly” defaultRedirect=”~/pagina-no-encontrada.aspx”>
<error statusCode=”404″ redirect=”~/pagina-no-encontrada.aspx”/>
<error statusCode=”500″ redirect=”~/error.aspx”/>
</customErrors>
El este pequeño ejemplo, estamos indicando al servidor IIS el modo en que debe atender las diferentes situaciones que puedan darse, concretamente para dos casos muy comunes: no localizar una dirección (código 404) o detectar un error en tiempo de ejecución (código 500).
- customErrors: permite configurar el modo en que se atiende un error.
- mode: modo en que debe comportarse el servidor de cara al error a la hora de mostrarlo
- on: mostrar una página de error genérica (o la indicada como por defecto para el error sucedido)
- off: mostrar cascada de error completa (PELIGRO DE SEGURIDAD, usar solo durante depuración y desarrollo), donde veremos una descripción detallada de lo sucedido
- RemoteOnly: mostrará una página de error genérica (o la indicada)
- defaultRedirect: lugar al que será enviado el usuario si no se indica nada para el suceso acontecido
- error: condición para un error concreto
- statuCode: código del error acontecido (po ejemplo… 200=OK; 301=movido; 404=no encontrado; 500=error de ejecución)
- redirect: página donde deberá ser llevado el usuario cuando suceda ese tipo de error
Ahora bien, si lo que queremos es poder realizar un tratamiento propio del error desde el fichero global, debemos tener en cuenta que lo anteriormente explicado, es decir, las instrucciones insertadas en el fichero de configuración web.config, se ejecutarán inmediatamente después de lo indicado en la función Application_Error salvo que le indiquemos lo contrario con la llamada a Server.ClearError(); , que retirará el error de la aplicación e ignorará lo aparecido en el fichero de configuración.
Tratemos ahora los otros dos casos: registro en Windows y envío por email.
Para registrar una excepción en el registro de Windows, podemos usar: (comprobando antes de nada que hayamos añadido al fichero System.Diagnostics)
EventLog.WriteEntry(“Test Web”,
“MESSAGE: ” + ex.Message +
“\nSOURCE: ” + ex.Source +
“\nFORM: ” + Request.Form.ToString() +
“\nQUERYSTRING: ” + Request.QueryString.ToString() +
“\nTARGETSITE: ” + ex.TargetSite +
“\nSTACKTRACE: ” + ex.StackTrace,
EventLogEntryType.Error);
Pero una cosa nos debe quedar muy clara: tras usar esto, la función en la que estamos será anulada instantáneamente, por lo que si queremos realizar cualquier otro tipo de atención a la excepción en la función Application_Error deberemos de hacerlo antes de llamar a EventLog.WriteEntry.
Si lo que deseamos es enviarnos el error por email, cosa que yo personalmente encuentro soberanamente útil, podremos usar: (haciendo uso de System.Net y System.Net.Mail)
string origen = “direccion@origen-de-aplicacion.com”;
string destino = “correo@electronicodedestino.com”;
string titulo = “Error de ejecución”;
string cuerpo = “<h2>Informe de error</h2>Fecha-hora: ” + DateTime.Now.ToString(“dd/MM/yyyy – HH:mm:ss”);
cuerpo += “<h3>Mensaje</h3>” + ex.Message + “<h3>StackTrace:</h3>” + ex.StackTrace + “<h3>TargetSite:</h3>” + ex.TargetSite;
MailMessage mensaje = new MailMessage(origen, destino, titulo, cuerpo);
mensaje.IsBodyHtml = true; //Si hemos añadido etiquetas HTML
SmtpClient smtp = new SmtpClient(“mismtp.midireccion.com”);
smtp.Timeout = 6000;
smtp.Send(mensaje);
Si teneis alguna duda o pega, no dudeis en comunicarmelo. Intentaré extender más este tipo de minitutoriales de ASP.NET y C#.