2012-05-22 22 views
11

Sto utilizzando l'evento FirstChanceException per registrare i dettagli di eventuali eccezioni generate.AppDomain.FirstChanceException e eccezione di overflow dello stack

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

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

Funziona come previsto. Ma se viene lanciata un'eccezione all'interno del gestore eventi, si verificherà un overflow dello stack poiché l'evento verrà generato in modo ricorsivo.

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

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

Come si gestiscono le eccezioni che si verificano all'interno del gestore eventi?

Edit:

Ci sono alcune risposte suggeriscono che ho avvolgere il codice all'interno del gestore di eventi in un blocco try/catch, ma questo non funziona in quanto l'evento viene generato prima che l'eccezione può essere gestita.

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

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

basta usare un campo bool per evitare la ricorsione. –

+0

Non capisco perché vorresti questo. Vengono gestite le prime eccezioni di possibilità. Perché mai ne butterei un altro? – leppie

+0

Non ne lancio intenzionalmente un altro. Cosa succede se sto cercando di registrare quell'errore e viene generata un'eccezione mentre sto cercando di registrare tali informazioni? – nivlam

risposta

-1

In deroga generale è possibile gestire come tutti gli altri, ma per quanto riguarda, in particolare, ad eccezione StackOverflow e OutOfMemory, non possono essere gestiti in .NET Framework.

Guardate qui: How do I prevent and/or handle a StackOverflowException? (C#)

partire dalla versione .NET Framework 2.0, un oggetto StackOverflowException non può essere catturato da un blocco try-catch e il corrispondente processo è terminato per impostazione predefinita. Di conseguenza, gli utenti sono invitati a scrivere il codice per rilevare e impedire uno stack overflow. Ad esempio, se l'applicazione dipende dalla ricorsione, utilizzare un contatore o una condizione per terminare il ciclo ricorsivo.

+0

Non sto cercando di rilevare un'eccezione StackOverflow. Sto cercando un modo per evitare che ciò accada. – nivlam

+0

@nivlam: per evitare che ciò accada, non chiamare la funzione che crea overflow dello stack in un * modo * che si chiama. Che soluzione stai cercando, quindi ?? – Tigran

-1

Penso aggiungendo un altro try {} catch(){} blocco del gestore di eccezioni avrebbe aiutato

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

Questo non funziona. L'evento FirstChanceException viene generato prima che l'eccezione possa essere gestita nel blocco catch. – nivlam

-1

maniglia interna eccezioni manualmente per esempio

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

L'articolo di MSDN si è collegato fa alcune raccomandazioni:

È necessario gestire tutte le eccezioni che si verificano nel gestore di eventi per l'evento FirstChanceException. Altrimenti, FirstChanceException viene generato in modo ricorsivo. Ciò potrebbe comportare un sovraccarico dello stack e la chiusura dell'applicazione. Si consiglia di implementare gestori di eventi per questo evento come aree di esecuzione vincolate (CER), per evitare che le eccezioni relative all'infrastruttura, come l'esaurimento della memoria o dello stack, influiscano sulla macchina virtuale durante l'elaborazione della notifica di eccezione.

Così racchiudono la funzione all'interno di un blocco try/catch, e chiamare PrepareConstrainedRegion prima del blocco per evitare eccezioni OutOfMemory: http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions.aspx

Edit: Beh, avete ancora il problema ricorsione anche con l'try/blocco di cattura. Quindi ... Immagino che devi solo chiamare solo un codice sicuro che non creerà alcuna eccezione. Quel gestore di eventi sembra abbastanza pericoloso, consiglierei di usarlo solo per scopi di debug.

+0

Problemi relativi alle prestazioni in ASP.NET? Ho una ** produzione di dump ** per la mia applicazione _ASP.NET 4.6.1_. Ci sono _7000 eccezioni_ (*** prime eccezioni di probabilità ***) in soli 20 minuti. Ho bisogno di log _first chance exceptions_ in modo sicuro per studiare il problema, senza ottenere *** stackoverflow o eccezioni outofmory *** – Kiquenet

0

Prima utilizzare un metodo, invece di un delegato, quindi il nome del metodo sarà definito

Quindi utilizzare Environment.StackTrace per verificare se il metodo è già nella stacktrace

Ecco un pezzo di codice non testati:

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

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

    // handle 
} 

credo che quanto sopra non funziona, perché sarà sempre contiene il nome del metodo, ma si può contare, se apparire più di 1 volta. Inoltre, controlla che non sia in linea quando compili in modalità di rilascio, in questo caso sei in difficoltà

+0

Cosa succede quando l'agente getter della proprietà 'Environment.StackTrace' genera un'eccezione? – hvd

+0

Perché dovrebbe lanciare? Doc (http://msdn.microsoft.com/en-us/library/system.environment.stacktrace.aspx) dice che può solo lanciare ArgumentOutOfRangeException ma non potrei in quel caso – Fabske

+0

Qualsiasi cosa può sempre lanciare un 'OutOfMemoryException' . Il che attiverà un'eccezione di prima scelta e tenterà di ottenere un'altra traccia dello stack, che fallirà anche perché non hai memoria. – hvd

1

Anche se non è un buon modo, in VB .NET puoi impedire l'attivazione di eccezioni all'interno del gestore di eventi FirstChanceException usando " In errore Riprendi successiva "istruzione, proveniente da VB 6. (Non sono sicuro che C# abbia qualcosa di simile) Inoltre, dovresti impedire la ricorsione sul gestore di eventi come menzionato here. Di seguito è riportato il codice di esempio, sembra funzionare come previsto.

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

Questo è il lavoro per me:

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

Questo è davvero il modo giusto per farlo, dovrebbe essere contrassegnato come risposta accettata. Potrebbe essere necessario aumentare il codice per occuparsi di diversi appdomain, ma, in caso contrario, bella soluzione! – Abel

+0

bella soluzione, hai salvato la mia giornata –

Problemi correlati