2010-06-28 17 views
159

Domanda: Desidero definire un gestore globale delle eccezioni per le eccezioni non gestite nella mia applicazione console. In asp.net, si può definire uno in global.asax, e in Windows applicazioni/servizi, si può definire come di seguito. Gestore di eccezioni globali .NET nell'applicazione console

AppDomain currentDomain = AppDomain.CurrentDomain; 
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyExceptionHandler); 

ma come posso definire un gestore di eccezioni globale per un'applicazione console?
currentDomain sembra non funzionare (.NET 2.0)?

Edit:

Argh, stupido errore.
In VB.NET, è necessario aggiungere la parola chiave "AddHandler" davanti a CurrentDomain oppure non viene visualizzato l'evento UnhandledException in IntelliSense ...
Questo perché i compilatori VB.NET e C# trattano la gestione degli eventi in modo diverso.

risposta

234

No, questo è il modo corretto per farlo. Questo ha funzionato esattamente come dovrebbe, qualcosa che si può lavorare da forse:

using System; 

class Program { 
    static void Main(string[] args) { 
     System.AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper; 
     throw new Exception("Kaboom"); 
    } 

    static void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e) { 
     Console.WriteLine(e.ExceptionObject.ToString()); 
     Console.WriteLine("Press Enter to continue"); 
     Console.ReadLine(); 
     Environment.Exit(1); 
    } 
} 

Non tenere a mente che non si può prendere tipo e caricare il file di eccezioni generate dal jitter in questo modo. Accadono prima che il metodo Main() inizi a girare. La cattura di quelli richiede il ritardo del jitter, sposta il codice rischioso in un altro metodo e applica l'attributo [MethodImpl (MethodImplOptions.NoInlining)] ad esso.

+0

Argh, stupido errore, ho bisogno di aggiungere AddHandler davanti AppDomain.CurrentDomain di vedere "UnhandledException" in VB.NET ... –

+2

ho implementato cosa hai proposto qui, ma non voglio uscire dall'applicazione. Voglio solo loggarlo e continuare il processo (senza 'Console.ReadLine()' o qualsiasi altro disturbo del flusso del programma, ma quello che ottengo è l'eccezione che si ripropone ancora e ancora, e ancora .. –

+1

@Shahrooz Jefri: Non è possibile continuare una volta ottenuta un'eccezione non gestita Lo stack è incasinato, e questo è terminale.Se si dispone di un server, ciò che è possibile fare in UnhandledExceptionTrapper è riavviare il programma con gli stessi argomenti della riga di comando. –

-7

Quello che stai provando dovrebbe funzionare secondo i documenti MSDN per .Net 2.0. Puoi anche provare a provare/catturare direttamente nella parte principale attorno al punto di ingresso per l'app della console.

static void Main(string[] args) 
{ 
    try 
    { 
     // Start Working 
    } 
    catch (Exception ex) 
    { 
     // Output/Log Exception 
    } 
    finally 
    { 
     // Clean Up If Needed 
    } 
} 

E ora il pescato in grado di gestire tutto quanto non catturato (nel thread principale). Può essere aggraziato e persino riavviare dove si trovava se lo si desidera, oppure è sufficiente lasciare che l'app muoia e registrare l'eccezione. Se lo volessi fare, ripuliresti definitivamente. Ogni thread richiede una gestione delle eccezioni di alto livello simile a quella principale.

Modificato per chiarire il punto sui fili come indicato da BlueMonkMN e mostrato in dettaglio nella sua risposta.

+1

Purtroppo le eccezioni possono ancora essere lanciate all'esterno del blocco Main(). Questo non è in realtà un "catch all" come si potrebbe pensare. Vedi la risposta di @Hans. –

+0

@Mike Per prima cosa ho detto che il modo in cui lo sta facendo è corretto e che potrebbe provare un tentativo/cattura nel main. Non sono sicuro del motivo per cui tu (o qualcun altro) mi hai dato un voto negativo quando stavo d'accordo con Hans, solo fornendo un'altra risposta che non mi aspettavo di ottenere un assegno. Non è giusto, e quindi dire che l'alternativa è sbagliata senza fornire alcuna prova su come un'eccezione può essere catturata dal processo AppDomain UnhandledException che un try/catch in Main non riesce a catturare.Trovo scortese dire che qualcosa non va senza provare perché è sbagliato, solo dire che è così, non è così. –

+0

È abbastanza ovvio che hai ridimensionato solo 4 dei miei vecchi post dal 2009 in rappresaglia. Prendi in considerazione la possibilità di modificare il tuo post e annullerò il mio downvote (e dovresti annullare i tuoi downward che mi hai dato, farò lo stesso). –

9

È inoltre necessario gestire le eccezioni da discussioni:

static void Main(string[] args) { 
Application.ThreadException += MYThreadHandler; 
} 

private void MYThreadHandler(object sender, Threading.ThreadExceptionEventArgs e) 
{ 
    Console.WriteLine(e.Exception.StackTrace); 
} 

Whoop, mi dispiace che è stato per WinForms, per qualsiasi thread che si sta utilizzando in un'applicazione di console si dovrà racchiudere in un try/catch bloccare. I thread in background che incontrano eccezioni non gestite non causano la fine dell'applicazione.

20

Se si dispone di un'applicazione a thread singolo, è possibile utilizzare un semplice try/catch nella funzione Main, tuttavia, questo non copre le eccezioni che possono essere generate all'esterno della funzione Main, su altri thread, ad esempio (come notato in altri commenti).Questo codice dimostra come un'eccezione può causare la chiusura dell'applicazione anche se si è tentato di gestirla in Main (notare come il programma si chiude con grazia se si preme enter e si consente all'applicazione di uscire con garbo prima che si verifichi l'eccezione, ma se si lascia che si esegua , termina piuttosto infelice):

static bool exiting = false; 

static void Main(string[] args) 
{ 
    try 
    { 
     System.Threading.Thread demo = new System.Threading.Thread(DemoThread); 
     demo.Start(); 
     Console.ReadLine(); 
     exiting = true; 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("Caught an exception"); 
    } 
} 

static void DemoThread() 
{ 
    for(int i = 5; i >= 0; i--) 
    { 
     Console.Write("24/{0} =", i); 
     Console.Out.Flush(); 
     Console.WriteLine("{0}", 24/i); 
     System.Threading.Thread.Sleep(1000); 
     if (exiting) return; 
    } 
} 

è possibile ricevere la notifica di quando un altro thread genera un'eccezione per eseguire alcuni pulire prima alla chiusura dell'applicazione, ma per quanto ne so, non si può, da un'applicazione console , forzare l'applicazione a continuare a funzionare se non si gestisce l'eccezione sul thread da cui viene generata senza utilizzare alcune opzioni di compatibilità oscure per far sì che l'applicazione si comporti come con .NET 1.x. Questo codice illustra come il filo conduttore può essere notificato di eccezioni provenienti da altri thread, ma sarà comunque terminerà infelice:

static bool exiting = false; 

static void Main(string[] args) 
{ 
    try 
    { 
     System.Threading.Thread demo = new System.Threading.Thread(DemoThread); 
     AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); 
     demo.Start(); 
     Console.ReadLine(); 
     exiting = true; 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("Caught an exception"); 
    } 
} 

static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 
{ 
    Console.WriteLine("Notified of a thread exception... application is terminating."); 
} 

static void DemoThread() 
{ 
    for(int i = 5; i >= 0; i--) 
    { 
     Console.Write("24/{0} =", i); 
     Console.Out.Flush(); 
     Console.WriteLine("{0}", 24/i); 
     System.Threading.Thread.Sleep(1000); 
     if (exiting) return; 
    } 
} 

Quindi, a mio parere, il modo più pulito di gestire la cosa in un'applicazione console è quello di garantire che ogni thread ha un gestore di eccezioni al livello principale:

static bool exiting = false; 

static void Main(string[] args) 
{ 
    try 
    { 
     System.Threading.Thread demo = new System.Threading.Thread(DemoThread); 
     demo.Start(); 
     Console.ReadLine(); 
     exiting = true; 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("Caught an exception"); 
    } 
} 

static void DemoThread() 
{ 
    try 
    { 
     for (int i = 5; i >= 0; i--) 
     { 
     Console.Write("24/{0} =", i); 
     Console.Out.Flush(); 
     Console.WriteLine("{0}", 24/i); 
     System.Threading.Thread.Sleep(1000); 
     if (exiting) return; 
     } 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("Caught an exception on the other thread"); 
    } 
} 
+0

TRY CATCH non funziona in modalità di rilascio per errori imprevisti: / – Muflix

Problemi correlati