lunes, 4 de abril de 2011

Como capturar TODOS los errores de una aplicación ASP.NET

En un interesante debate en AltNetHispano, hemos estado dando vueltas a cómo evitar que una excepción llegue a la capa de representación.
La mejor práctica sería tener controladas las excepciones con un try-catch en los sitios adecuados y una clase o clases que sepan que hacer en cada caso.
Pero, y como muestra de una mala práctica levada a cabo por motivos más que oscuros, he enseñado un código que hicimos que se traga TODOS las expeciones sin dejar la más mínima traza:
En el fichero Global.asax. Si ese que casi nadie se acuerda de que aún existe y tiene muchas cosas buenas. Ponemos:
void Application_Error(object sender, EventArgs e)
{
  Context.Server.ClearError();
  Response.Redirect(Request.RawUrl);
}
Si en vez de la barbaridad que pusimos en su momento, lo utilizas como punto único de captura de las excepciones y lo mandas a las clases adecuadas, te facilitas mucho la vida utilizando las herramientas que el propio asp.net nos ofrece. Y evitamos estar reinventando la rueda haciendo Handles globales para las excepciones.

4 comentarios:

Julípides dijo...

Buenas...a nosotros lo que nos suele interesar saber es, sobre todo, conocer la razón (esto no tanto) y el origen exacto del error. Así que, más que nada porque los programadores son vagos, casi en cualquier método de cualquier case lo que hacemos es lo siguiente (GTPV es nuestra aplicación):

Sub HacerAlgo()
Dim oExcepcion As ExcepcionGTPV = Nothing
Try
HacerAlgo...

Catch exc As ExcepcionGTPV
oExcepcion = exc

Catch ex As Exception
oExcepcion = New ExcepcionGTPV() With {.Proyecto = Me.GetType.Assembly.FullName,
.Clase = Me.GetType.Namespace + "." + Me.GetType.Name...
End Try

If oExcepcion IsNot Nothing Then
Throw oExcepcion
End If

End Sub

Julípides dijo...

Decía lo de vagos, porque el primer Catch muchas veces no es necesario (sólo se llama a otro método o clase)... y porque sólo mostramos el objeto excepción en una ventana propia de errores en el punto de partida de la llamada (ej: click de un botón). Así que mi táctica ha tenido que sea que pongan el mismo código en todas partes y luego en la revisión del código, corregir dónde se ha hecho mal. Si no lo hago así, tengo que revisarel tratamiento de excepciones en todo el código, porque te encuentras variantes de todo tipo: que falte precisamente el Catch que es necesario, la ausencia de try, o incluso un Show del error en una capa que no es de presentación...

En resumen, que me funciona mucho mejor pedir que se haga sólo copy-paste que pensar-copiar-pegar. Es triste, pero es así, dejar la parte de pensar sólo para quienes sé que lo hacen bien y siempre (pocos, por desgracia).

Juan Quijano dijo...

Varias cosillas Julio:
* Con un ex.ToString() te sale la pila completa del mensaje.

* Me parece que adoleces de test unitarios. Es solo una suposición.

* Es un antipatrón el copy&paste. Yo haría una clase con un método estático para tratar las excepciones. Y si no quieres poner un try catch en cada método, usa el global.axa o un handler global (que es lo mismo).

* Lo de la parte de pensar es una filosofía que no comparto. El equipo es equipo y las decisiones han de ser entre todos. Si divides entre los que saben pensar y los que no... la cosa se te va a poner fea por momentos :P Los que no piensan no se responsabilizan de su código, por lo cual no están motivados y rinden solamente lo justo para cubrir lo que dicen los que piensan.

Julípides dijo...

Sí, tienes razón en casi todo lo que me comentas, salvo en una cosa: yo no he dividido a la gente entre los que piensan y los que no. Es algo que en el día a día, se ha demostrado que, por desgracia, es así (y no debería, en eso sí tienes razón).

Pero es que aquí tenemos a gente muy muy novata, a los que normalmente encomiendan siempre tareas muy simples. En cuanto les metes tareas con un alcance algo mayor, se pierden, porque están acostumbrados a hacer cosas por pura obediencia, sin pararse a pensar en lo que hacen. Intentamos de todo: dar formación, explicar al máximo, reuniones tipo scrum diarias, darles mil ejemplos de código bueno (de la propia solución, no ejemplos teóricos)... y no funcionó nada, simplemente porque la gente no tiene nivel.

Otra tendencia de mis programadores es la de ocultar permanentemente y por sistema sus dudas y lagunas técnicas. Piensan que reconocer que no entender o saber hacer algo es un fracaso. Consecuencia: les pides que hagan una consulta lanzada por un botón, y para ellos el objetivo es que "salga algo", y les da igual que cómo y qué.

Todo esto es algo que con un equipo muy corto, puedes correghir y encauzar, pero cuando el equipo es (ha sido, mejor dicho) es de ocho personas, de las cuales, seis tienen un nivel pobre y malas costumbres adquiridas, acabas luchando contra molinos de viento. Y en esas condiciones, da igual que apliques scrum, agile o lo que sea.