2008-11-17 47 views
29

Tengo un sitio web creado en C# .NET que tiende a producir un flujo constante de tiempos de espera de SQL de varios controles de usuario y quiero introducir fácilmente algunos códigos para capturar todos excepciones no controladas y enviarlas a algo que pueda registrarlas y mostrar un mensaje amigable al usuario.Manera fácil de detectar todas las excepciones no controladas en C# .NET

¿Cómo puedo, a través del mínimo esfuerzo, detectar todas las excepciones no controladas?

this question parece decir que es imposible, pero eso no tiene sentido para mí (Y se trata de .NET 1.1 en aplicaciones de Windows):

+3

¿No es eso el tratamiento de los síntomas y no la causa? es decir, ¿no debería estar mirando la causa de los tiempos de espera de SQL ejecutando un rastreo del Analizador de SQL en el servidor de la base de datos? –

+1

Creo que debes aclarar lo que quieres decir con "catch": como en try ...detecte dónde puede manejar la excepción, o si simplemente desea que se le informe una excepción no controlada, y registre dónde/cuándo (por ejemplo, ELMAH) –

Respuesta

2

Qué quiere decir la manipulación en todos los temas, incluyendo los creados por el tercer ¿código de fiesta? Dentro de los hilos "conocidos" simplemente tome Exception en la parte superior de la pila.

25

Todas las excepciones no controladas finalmente pasaron a través de Application_Error en global.asax. Entonces, para dar un mensaje de excepción general o hacer operaciones de registro, vea Application_Error.

+10

busque en la primera oración; "Tengo un sitio web creado en C# .NET que tiende ..." –

+3

Para cualquiera que intente descubrir lo que dice el comentario anterior, supongo que está respondiendo un comentario ahora eliminado. (Sugerencia: vea quién escribió la respuesta y quién escribió el comentario.) – ispiro

+0

Es posible que necesite establecer '' en web.config. Sin esta entrada, no estaba funcionando en el servidor de producción para mí. – ghord

1

Recomendaría mirar log4net y ver si eso es adecuado para la parte de registro de la pregunta.

16

Si usted necesita coger Excepciones en todas las discusiones es la mejor aproach para implementar UnhandledExceptionModule y agregarlo a la consulta de aplicación que here para un ejemplo

+0

La pregunta se refiere a las aplicaciones de Windows, no a las aplicaciones web. – RoadWarrior

+13

"Tengo un sitio web creado en C# .NET" – annakata

7

Usted puede suscribirse al evento AppDomain.CurrentDomain.UnhandledException.

+0

A partir de 2.00 esto no capta la excepción, solo le da la oportunidad de iniciar sesión. Sin embargo, lo hizo en 1.0 -> 1.1, pero ese fue un error corregido en 2.00. Creo que también necesita Application.ThreadException o algo así para obtener una cobertura completa. – Quibblesome

+0

De acuerdo, pero la intención del OP parece ser iniciar sesión y redirigir, no atrapar. Y Application.ThreadException es para WinForms, no para WebForms. –

+0

Creo que Quarrelsome es correcto porque la pregunta del OP se refiere a las aplicaciones de Windows en lugar de a las aplicaciones web. – RoadWarrior

1

Hay 2 partes a este problema manejando & identificando.

Identificar

Esto es lo que haces cuando la excepción es finalmente atrapado, no necesariamente en el que se lanza. Así que la excepción en esta etapa debe tener suficiente información de contexto para que usted pueda idenitfy lo que el problema era

Manejo

Para manipulación, puede a) añadir un HttpModeule. Ver http://www.eggheadcafe.com/articles/20060305.asp que sugeriría este enfoque sólo cuando no hay absolutamente ninguna informaatn contexto disponible y puede haber issuus wiih IIS/Red PEA, en definitiva para situaciones catastróficas

b) Crear una clase abstracta llamada AbstractBasePage que deriva de la clase de página y todas sus clases de código subyacente derivan de AbstractBasePage

AbstractBasePage puede implementar esa página.Error delegado para que todas las excepciones que se filtran a través de la arquitectura n-tier puedan capturarse aquí (y posiblemente registrarse)

Sugeriría esta causa para el tipo de excepciones de las que está hablando (SQlException) hay suficiente información de contexto para que identifique que fue un tiempo de espera y tome medidas posibles. Esta acción podría incluir redirigir al usuario a una página de error personalizada con el mensaje apropiado para cada tipo de excepción (Sql, servicio web, tiempos de espera de llamadas asincrónicas, etc.).

Gracias RVZ

13

Utilice el método Application_Error en el archivo Global.asax. Dentro de la implementación de su método Application_Error, llame a Server.GetLastError(), registre los detalles de la excepción devuelta por Server.GetLastError() como lo desee.

p. Ej.

void Application_Error(object sender, EventArgs e) 
{ 
    // Code that runs when an unhandled error occurs 
    log4net.ILog log = log4net.LogManager.GetLogger(typeof(object)); 
    using (log4net.NDC.Push(this.User.Identity.Name)) 
    { 
     log.Fatal("Unhandled Exception", Server.GetLastError()); 
    } 
} 

No prestar demasiada atención a las cosas log4net, Server.GetLastError() es el bit más útil, registrar los detalles sin embargo se prefiere.

8

El ELMAH project suena la pena intentarlo, su lista de características incluyen:

(Módulos del registro de error y Manipuladores) ELMAH es una función de registro de error en toda la aplicación que es completamente enchufable. Se puede agregar dinámicamente a una aplicación web ASP.NET en ejecución, o incluso todas las aplicaciones web ASP.NET en una máquina, sin necesidad de recompilar o redistribuir.

  • Registro de casi todas las excepciones no controladas.
  • Una página web para ver de forma remota todo el registro de excepciones recodificadas.
  • Una página web para ver de forma remota todos los detalles de una excepción registrada con .
  • En muchos casos, puede revisar la pantalla amarilla original de la muerte que ASP.NET generó para una excepción dada , incluso con el modo customErrors apagado.
  • Notificación por correo electrónico de cada error en el momento en que ocurre.
  • Una fuente RSS de los últimos 15 errores del registro.
  • Un número de implementaciones de almacenamiento de respaldo para el registro de

más sobre el uso de ELMAH dotnetslackers

3

Es probable que sea importante tener en cuenta que son no supone para atrapar las excepciones no controladas. Si tiene problemas de tiempo de espera de SQL, debería detectarlos específicamente.

+0

Su argumento "Probablemente es importante tener en cuenta que no debe atrapar excepciones no controladas". es completamente ilógico (sin referencias, razones, etc.). Además, ¿has oído hablar de la declaración 'throw'? –

+0

Proporcionaré más información. Microsoft no quiere que atrape (Excepción). Fallará la certificación del logotipo de Windows. Tampoco se supone que debes lanzar una nueva Excepción, se supone que lanzas una ApplicationException. Se supone que siempre debe detectar la excepción más específica que tenga sentido. –

+0

Capturar cualquier excepción, iniciar sesión y luego arrojarla es útil. Creo que lo peor que las personas pueden hacer es rodear todo su código en try-catch's ... o incluso peor flujo de dictado basado en try-catch. Por ejemplo, tengo un programa que tiene un delegado adjunto a UnhandledException, por lo que cada vez que algo no se maneja, obtengo la excepción. Que luego envío a un servicio web y dejo que se cuelgue mi software. ¿De qué otra manera vas a descubrir qué salió mal? –

1

Los errores de tiempo de espera suelen producirse si no cierra a la fuerza sus conexiones sql.

así que si tenía un

try { 
    conn.Open(); 
    cmd.ExecuteReader(); 
    conn.Close(); 
} catch (SqlException ex) { 
    //do whatever 
} 

Si algo va mal con su conexión ExecuteReader que no se cerrará. Siempre agregue un bloque finally.

try { 
    conn.Open(); 
    cmd.ExecuteReader(); 
    conn.Close(); 
} catch (SqlException ex) { 
    //do whatever 
} finally { 
    if(conn.State != ConnectionState.Closed) 
     conn.Close(); 
} 
+1

-1: tiene cuatro meses de retraso y no implementa bloques 'using', que son la forma correcta de evitar el problema del que está hablando. –

+0

no están usando bloques haciendo lo mismo s finalmente? –

+0

btw de C# Referencia: La sentencia using garantiza que se invoque Dispose incluso si se produce una excepción mientras se están llamando métodos al objeto. Puede lograr el mismo resultado colocando el objeto dentro de un bloque try y luego llamando a Dispose en un bloque finally; de hecho, así es como el compilador traduce la sentencia using. –

1

Una respuesta breve es utilizar métodos de delegado (anónimos) con código de manejo común cuando se invoca al delegado.

Antecedentes: Si ha orientado los puntos débiles, o tiene algún código de manejo de errores repetitivo es necesario aplicar universalmente a una clase particular de problema, y ​​que no desea escribir el mismo para try..catch cada ubicación de invocación (como actualizar un control específico en cada página, etc.).

Estudio de caso: Un punto importante es la creación de formularios web y el guardado de datos en la base de datos. Tenemos un control que muestra el estado guardado al usuario, y queríamos tener un código de manejo de errores común así como una visualización común sin copiar-pegar-reutilizar en cada página. Además, cada página hacía su propia cosa a su manera, por lo que la única parte realmente común del código era el manejo y visualización de errores.

Ahora, antes de ser cerrado, esto no reemplaza una capa de acceso a datos y un código de acceso a datos. Todavía se supone que existe, una buena separación de n niveles, etc. Este código es específico de la capa UI para permitirnos escribir códigos de UI limpios y no repetirnos. Creemos firmemente en no anular las excepciones, pero ciertas excepciones no deberían obligar al usuario a obtener una página de error genérica y perder su trabajo. Habrá tiempos de espera de SQL, servidores bajan, bloqueos, etc.

Una solución: La forma en que lo hicimos fue pasar un delegado anónimo a un método en un control personalizado y esencialmente inyectar el bloque try usando delegados anónimos .

// normal form code. 
private void Save() 
{ 
    // you can do stuff before and after. normal scoping rules apply 
    saveControl.InvokeSave(
     delegate 
     { 
      // everywhere the save control is used, this code is different 
      // but the class of errors and the stage we are catching them at 
      // is the same 
      DataContext.SomeStoredProcedure(); 
      DataContext.SomeOtherStoredProcedure(); 
      DataContext.SubmitChanges(); 
     }); 
} 

El SaveControl en sí tiene un método similar:

public delegate void SaveControlDelegate(); 

public void InvokeSave(SaveControlDelegate saveControlDelegate) 
{   
    // I've changed the code from our code. 
    // You'll have to make up your own logic. 
    // this just gives an idea of common handling. 
    retryButton.Visible = false; 
    try 
    { 
     saveControlDelegate.Invoke(); 
    } 
    catch (SqlTimeoutException ex) 
    { 
     // perform other logic here. 
     statusLabel.Text = "The server took too long to respond."; 
     retryButton.Visible = true; 
     LogSqlTimeoutOnSave(ex); 
    } 
    // catch other exceptions as necessary. i.e. 
    // detect deadlocks 
    catch (Exception ex) 
    { 
     statusLabel.Text = "An unknown Error occurred"; 
     LogGenericExceptionOnSave(ex); 
    } 
    SetSavedStatus(); 
} 

  • Hay otras maneras de lograr esto (por ejemplo clase base común, intefaces), pero en nuestro caso esto tenía el mejor ajuste.
  • Esto no es un reemplazo de una gran herramienta como Elmah para registrar todas las excepciones no controladas. Este es un enfoque específico para manejar ciertas excepciones de manera estándar.
0

Esta es la vieja pregunta, pero el mejor método (para mí) no aparece aquí. Así que aquí estamos:

ExceptionFilterAttribute es una solución agradable y fácil para mí. Fuente: http://weblogs.asp.net/fredriknormen/asp-net-web-api-exception-handling.

public class ExceptionHandlingAttribute : ExceptionFilterAttribute 
{ 
    public override void OnException(HttpActionExecutedContext context) 
    { 
     var exception = context.Exception; 
     if(exception is SqlTimeoutException) 
     { 
      //do some handling for this type of exception 
     } 
    } 
} 

Y añádelo a f.e. HomeController:

[ExceptionHandling] 
public class HomeController: Controller 
{ 

} 
Cuestiones relacionadas