2009-08-19 4 views
6

Questo è relativo a previous question.Perché le eccezioni AppDomain terminano invariabilmente l'applicazione?

Quello che sto cercando di capire ora è come le eccezioni del thread dell'interfaccia utente possono essere impedite dal terminare l'applicazione mentre le eccezioni non-UI non possono essere.

Per riferimento, vedere this example.

Ancora più importante, quello che vorrei essere in grado di fare in quel caso è "silenziosamente" terminare il processo - senza visualizzare la finestra di dialogo di Windows che chiede se mi piacerebbe inviare un rapporto di errore o meno.

Questo è il mio dominio di applicazione UnhandledExceptionHandler:

private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 
{    
    try 
    { 
     // Maybe do some logging here if allowed 
    } 
    catch 
    { 
    } 

    // then just terminate the application 
    Application.Exit();    
} 

UPDATE
Alla luce delle osservazioni in this answer, vorrei precisare che la cosa più importante mi piacerebbe saperne di più circa il meccanismo che consente al thread dell'interfaccia utente di avere una prima opportunità di rilevare eccezioni non gestite tramite il meccanismo Application.ThreadException. E se tale comportamento potrebbe essere implementato su un thread non UI.

risposta

7

Così, dopo aver fatto qualche altra ricerche su Google ho trovato questa spiegazione molto interessante che è stato dato lo stesso problema come descritto da Jeff Atwood on his blog.

Ciao a tutti, Ci scusiamo per la confusione. Questo comportamento è in realtà il design, anche se il design può essere un po 'contorto a volte.

La prima cosa da capire è che l'evento UnhandledException non è un'eccezione "gestore" non gestita. La registrazione per l'evento, contrariamente a quanto dice la documentazione :-(, non causa eccezioni non gestite da gestire (Da allora non sarebbero state gestite, ma mi fermerò con il ragionamento circolare già ...) L'evento UnhandledException semplicemente avvisa che un'eccezione è andato non gestita, nel caso in cui si desidera cercare di salvare lo stato prima del tuo thread o applicazione muore. FWIW, ho presentato un bug per ottenere la documentazione fissi.

Solo per complicare le cose, in v1.0 e 1.1, un'eccezione non gestita non significava sempre che la domanda sarebbe morta. Se l'eccezione non gestita si è verificata su qualcosa di diverso dal thread principale o da un thread che ha iniziato la sua vita in codice non gestito, il CLR ha mangiato l'eccezione e ha consentito alla tua app di continuare. Questo era generalmente malvagio, perché ciò che accadeva spesso era, ad esempio, che i thread ThreadPool si spegnevano silenziosamente, uno per uno, fino a quando l'applicazione non stava effettivamente facendo alcun lavoro. Capire la causa di questo tipo di fallimento era quasi impossibile. Questo potrebbe essere il motivo per cui Jeff ha pensato che funzionasse prima ... ha sempre visto crash su thread non principali.

Nella v2.0, un'eccezione non gestita su qualsiasi thread interromperà l'applicazione. Abbiamo scoperto che è tremendamente più facile eseguire il debug degli arresti anomali di quanto non sia il blocco del debug o il problema del blocco silenzioso descritto sopra.

BTW, sulla mia macchina 1.1 l'esempio da MSDN ha l'output previsto; è solo che la seconda riga non viene visualizzata fino a quando non hai collegato un debugger (o meno). In v2 abbiamo capovolto le cose in modo che l'evento UnhandledException si attivi prima che il debugger si attachi, il che sembra essere quello che la maggior parte della gente si aspetta.

Jonathan Keljo CLR eccezioni PM Jonathan Keljo il 18 febbraio 2005 10:02

Tuttavia, sono ancora interessato a come thread dell'interfaccia utente compie il trucco di consentire di avere un fermo -Tutto gestore per tutte le eccezioni del thread UI.

Ancor più, sono molto interessati ad un modo per disattivare il debug di dialogo .NET JIT per la mia applicazione solo (senza disabling it for the whole machine as seen here)

3

Non è che nessuna eccezione AppDomain interrompa l'applicazione, è che le eccezioni non gestite (di qualsiasi tipo) interromperanno l'AppDomain e interromperanno l'applicazione.

Il problema qui è che è possibile gestire le eccezioni del thread UI in modo esplicito, ad un livello abbastanza alto. Tuttavia, quando si ha un'eccezione non gestita in un thread in background, non c'è modo di gestirlo facilmente allo stesso livello, quindi tende a propagarsi e a rilasciare l'applicazione. Application.ThreadException ti consente almeno di sapere che questo è ciò che ha causato l'errore e, se necessario, registrarlo.

Eccezioni non gestite nel thread dell'interfaccia utente causeranno la stessa cosa.

+0

@Reed: "le eccezioni non gestite nel thread UI causerà lo stesso cosa succederà. " - questo non è vero. Si prega di creare un'applicazione di prova e provarla personalmente. –

+1

Tecnicamente, avrei dovuto dire "Eccezioni non gestite sul thread principale". Windows Form aggiunge il proprio comportamento di gestione delle eccezioni sul thread dell'interfaccia utente (poiché è interamente in esecuzione sul thread dell'interfaccia utente) che modifica il comportamento del thread principale. Crea un'applicazione per console, e prova questo, e vedrai che non importa quale argomento avvenga: tutti abbatteranno l'applicazione. –

+0

Quindi dovrei riaffermare la mia domanda: in che modo il thread UI realizza il suo comportamento generale di gestione delle eccezioni? È qualcosa che potrei replicare come comportamento per un thread non UI? –

2

Questo può aiutare?

Improved Unhandled Exception behavior in .NET 2.0

Inoltre, questo codice sembra "morire in silenzio". Stai cercando qualcos'altro?

using System; 

namespace UnhandledException 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException; 

      throw new NotImplementedException(); 
     } 

     static void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e) 
     { 
      Exception exception = (Exception)e.ExceptionObject; 
      System.Console.WriteLine("exception=[" + exception.ToString() + "]"); 

      Environment.Exit(-1); 
     } 
    } 
} 
+0

Sì. Ho appena finito di leggere il post e i commenti quando l'hai postato. +1 comunque .. –

+0

Sì, Environemnt.Exit sembra fare il trucco! Lascerò le domande aperte ancora per un po 'di tempo per vedere se qualcuno può dare un'idea di come il thread dell'interfaccia utente realizza l'eccezione catch-all. Altrimenti avrai il mio voto per la risposta accettata! –

+0

Application.ThreadException è solo un'altra variante di un "gestore di eccezioni non gestito". Esistono molte varianti (Console App vs. WinForms vs WebForms vs. WCF, ecc.). Non sono sicuro di aver capito la tua domanda. In generale, attuo tutti quelli che sono applicabili. –