2012-05-22 17 views
11

Estoy usando el evento FirstChanceException para registrar detalles sobre cualquier excepción lanzada.AppDomain.FirstChanceException y excepción de desbordamiento de pila

static void Main(string[] args) 
{ 
    AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) => 
    { 
     Console.WriteLine("Inside first chance exception."); 
    }; 

    throw new Exception("Exception thrown in main."); 
} 

Esto funciona como se esperaba. Pero si se lanza una excepción dentro del controlador de eventos, se producirá un desbordamiento de la pila ya que el evento se generará recursivamente.

static void Main(string[] args) 
{ 
    AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) => 
    { 
     throw new Exception("Stackoverflow"); 
    }; 

    throw new Exception("Exception thrown in main."); 
} 

¿Cómo manejo las excepciones que se producen en el controlador de eventos?

Editar:

Hay algunas respuestas que sugieren que envuelvo el código dentro del controlador de eventos en un bloque try/catch, pero esto no funciona ya que el evento se produce antes de que la excepción puede ser manejado.

static void Main(string[] args) 
{ 
    AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) => 
    { 
     try 
     { 
      throw new Exception("Stackoverflow"); 
     } 
     catch 
     { 
     } 
    }; 

    throw new Exception("Exception thrown in main."); 
} 
+0

sólo tiene que utilizar un campo booleano para evitar la repetición. –

+0

No entiendo por qué quieres esto. Se manejan las excepciones de la primera oportunidad. ¿Por qué demonios arrojarías otro? – leppie

+0

No estoy intencionalmente lanzando otro. ¿Qué sucede si intento registrar ese error y se produce una excepción mientras trato de registrar esa información? – nivlam

Respuesta

-1

En excepción general que puede manejar como todos los demás, pero ¿y en particular StackOverflow y OutOfMemory excepción, que no pueden ser manejados de .NET Framework.

vistazo aquí: How do I prevent and/or handle a StackOverflowException? (C#)

A partir de la versión 2.0 de .NET Framework, un objeto StackOverflowException no puede ser atrapado por un bloque try-catch y el proceso correspondiente se termina por defecto. En consecuencia, se recomienda a los usuarios que escriban su código para detectar y evitar un desbordamiento de la pila. Por ejemplo, si su aplicación depende de la recursión, use un contador o una condición de estado para terminar el ciclo recursivo.

+0

No estoy buscando atrapar una excepción de stackoverflow. Estoy buscando una forma de evitar que suceda. – nivlam

+0

@nivlam: para evitar que suceda, no llame a la función que crea el desbordamiento de pila de * manera * que lo llame. ¿Qué solución estás buscando, entonces? – Tigran

-1

creo que la adición de otro bloque try {} catch(){} en el gestor de excepciones ayudaría

static void Main(string[] args) 
{ 
    AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) => 
    { 
     try { 
      throw new Exception("Stackoverflow"); 
     } catch (Exception e) 
     { 
      // Do something very simple not throwing an exception... 
     } 
    }; 

    throw new Exception("Exception thrown in main."); 
} 
+1

Esto no funciona. El evento FirstChanceException se genera antes de que la excepción pueda ser manejada en el bloque catch. – nivlam

-1

manija dentro excepciones manualmente, por ejemplo,

static void Main(string[] args) { 
    AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) => 
    { 
     try{ 
     throw new Exception("Stackoverflow");} catch (Exception ex){/*manual handle*/} 
    }; 
     throw new Exception("Exception thrown in main."); 
} 
0

El artículo de MSDN se conectó hace unos recommandations:

Debe manejar todas las excepciones que se producen en el controlador de eventos para el evento FirstChanceException. De lo contrario, FirstChanceException se genera recursivamente. Esto podría provocar un desbordamiento de la pila y la finalización de la aplicación. Recomendamos que implemente controladores de eventos para este evento como regiones de ejecución restringidas (CERs), para evitar que las excepciones relacionadas con la infraestructura, como la falta de memoria o el desbordamiento de la pila, afecten a la máquina virtual mientras se procesa la notificación de excepción.

Así que encierran su función dentro de un bloque try/catch, y llaman PrepareConstrainedRegion antes del bloque para evitar excepciones OutOfMemory: http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions.aspx

Editar: Bueno, usted todavía tiene el problema de recursividad incluso con el try/atrapar bloque Entonces ... supongo que solo debes llamar al código seguro que no lanzará ninguna excepción. Ese controlador de eventos parece bastante peligroso, recomendaría usarlo solo para fines de depuración.

+0

¿Algún problema de rendimiento en ASP.NET? Tengo una ** producción de volcado ** para mi aplicación _ASP.NET 4.6.1_. Hay _7000 excepciones_ (*** excepciones de primera oportunidad ***) en solo 20 minutos. Necesito registrar _primeras excepciones de oportunidad_ de forma segura para estudiar el problema, sin obtener *** excepciones de stackoverflow o outofmemory *** – Kiquenet

0

primer lugar, utilice un método en lugar de un delegado, por lo que el nombre del método se definirá

A continuación, utilice Environment.StackTrace para comprobar si el método ya está en el StackTrace

Aquí es una pieza de código no probado:

static void Main(string[] args) 
{ 
    AppDomain.CurrentDomain.FirstChanceException += handleFirstChanceException; 
} 

private void handleFirstChanceException(object sender, EventArgs eventArgs) 
{ 
    if (Environment.StackTrace.Contains("handleFirstChanceException")) 
     return; 

    // handle 
} 

Creo que lo anterior no funciona, ya que siempre va contiene el nombre del método, pero se puede contar si aparecen más de 1 hora. Además, compruebe que no está alineado cuando compila en modo Release, en este caso está en problemas

+0

¿Qué sucede cuando el getter de propiedad 'Environment.StackTrace' arroja una excepción? – hvd

+0

¿Por qué debería lanzar? Doc (http://msdn.microsoft.com/en-us/library/system.environment.stacktrace.aspx) dice que solo puede lanzar una ArgumentOutOfRangeException, pero no pude, en cuyo caso – Fabske

+0

Anything siempre puede lanzar una 'OutOfMemoryException' . Lo cual activará una excepción de primera oportunidad e intentará obtener otra traza de pila, que también fallará, ya que se ha quedado sin memoria. – hvd

1

Aunque no es una buena manera, en VB .NET puede evitar la activación de excepciones dentro del controlador de eventos FirstChanceException utilizando " En la reanudación de la instrucción Error "Next", procedente de VB 6. (No estoy seguro de que C# tenga algo similar). Además, debe evitar la recursión en el controlador de eventos como se menciona here. A continuación se muestra el código de muestra, parece funcionar como se esperaba.

Sub Main(args As String()) 
    AddHandler AppDomain.CurrentDomain.FirstChanceException, AddressOf FirstChanceExceptionEventHandler 
    Throw New Exception("Exception thrown in main.") 
End Sub 

Private Sub FirstChanceExceptionEventHandler(ByVal source As Object, ByVal e As FirstChanceExceptionEventArgs) 
    On Error Resume Next 

    Dim frames As StackFrame() = New StackTrace(1).GetFrames() 
    Dim currentMethod As MethodBase = MethodBase.GetCurrentMethod() 
    If frames IsNot Nothing AndAlso frames.Any(Function(x) x.GetMethod() = currentMethod) Then 
     Return 
    Else 
     Throw New Exception("Stackoverflow") 
    End If 
End Sub 
4

Esto es trabajo para mí:

private volatile bool _insideFirstChanceExceptionHandler;  

// ... 

AppDomain.CurrentDomain.FirstChanceException += OnFirstChanceException; 

// ... 

private void OnFirstChanceException(object sender, FirstChanceExceptionEventArgs args) 
{ 
    if (_insideFirstChanceExceptionHandler) 
    { 
     // Prevent recursion if an exception is thrown inside this method 
     return; 
    } 

    _insideFirstChanceExceptionHandler = true; 
    try 
    { 
     // Code which may throw an exception 
    } 
    catch 
    { 
     // You have to catch all exceptions inside this method 
    } 
    finally 
    { 
     _insideFirstChanceExceptionHandler = false; 
    } 
} 
+0

Esta es la forma correcta de hacerlo, debe marcarse como la respuesta aceptada. Sin embargo, es posible que tengas que aumentar el código para ocuparte de diferentes aplicaciones, ¡pero de lo contrario, buena solución! – Abel

+0

buena solución, me salvaste el día –

Cuestiones relacionadas