Domanda

Mi chiedo quale sia il modo migliore per avere un " se tutto il resto non riesce a prenderlo " ;.

Voglio dire, stai gestendo quante più eccezioni possibili nella tua applicazione, ma comunque ci saranno sicuramente dei bug, quindi devo avere qualcosa che rileva tutte le eccezioni non gestite in modo che io possa raccogliere informazioni e archiviarle in un database o inviarli a un servizio Web.

L'evento AppDomain.CurrentDomain.UnhandledException acquisisce tutto? Anche se l'applicazione è multithread?

Nota a margine: Windows Vista espone le funzioni API native che consentono qualsiasi applicazione per riprendersi dopo un incidente ... non riesco a pensare al nome ora ... ma preferirei di no usalo, poiché molti dei nostri utenti utilizzano ancora Windows XP.

È stato utile?

Soluzione

Ho appena giocato con il comportamento UnhandledException di AppDomain, (questa è l'ultima fase in cui è registrata l'eccezione non gestita)

Sì, dopo aver elaborato i gestori di eventi l'applicazione verrà chiusa e il cattivo programma "quot" ... smetterà di funzionare nella finestra di dialogo " mostrato.

:) ancora puoi evitarlo.

Check out:

class Program
{
    void Run()
    {
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

        Console.WriteLine("Press enter to exit.");

        do
        {
            (new Thread(delegate()
            {
                throw new ArgumentException("ha-ha");
            })).Start();

        } while (Console.ReadLine().Trim().ToLowerInvariant() == "x");


        Console.WriteLine("last good-bye");
    }

    int r = 0;

    void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Interlocked.Increment(ref r);
        Console.WriteLine("handled. {0}", r);
        Console.WriteLine("Terminating " + e.IsTerminating.ToString());

        Thread.CurrentThread.IsBackground = true;
        Thread.CurrentThread.Name = "Dead thread";            

        while (true)
            Thread.Sleep(TimeSpan.FromHours(1));
        //Process.GetCurrentProcess().Kill();
    }

    static void Main(string[] args)
    {
        Console.WriteLine("...");
        (new Program()).Run();
    }
}

P.S. Gestisce il non gestito per Application.ThreadException (WinForms) o DispatcherUnhandledException (WPF) al livello superiore.

Altri suggerimenti

In ASP.NET, si utilizza la funzione Application_Error nel file Global.asax .

In WinForms, si utilizza MyApplication_UnhandledException nel file ApplicationEvents

Entrambe queste funzioni vengono chiamate se si verifica un'eccezione non gestita nel codice. Puoi registrare l'eccezione e presentare un bel messaggio all'utente da queste funzioni.

Per le applicazioni Winform, oltre ad AppDomain.CurrentDomain.UnhandledException, utilizzo anche Application.ThreadException e Application.SetUnhandledExceptionMode (con UnhandledExceptionMode.CatchException). Questa combinazione sembra catturare tutto.

Sul thread principale, hai le seguenti opzioni:

Per altri thread:

  • I thread secondari non hanno eccezioni non gestite; usa SafeThread
  • Discussioni dei lavoratori: (timer, threadpool) non esiste alcuna rete di sicurezza!

Tieni presente che questi eventi non gestiscono le eccezioni, ma semplicemente segnalano all'applicazione - spesso quando è troppo tardi per fare qualcosa di utile / sano su di loro

La registrazione delle eccezioni è buona, ma il monitoraggio delle applicazioni è migliore ;-)

Avvertenza: sono l'autore dell'articolo SafeThread .

Per WinForms, non dimenticare di collegarti anche all'evento di eccezione non gestita del thread corrente (specialmente se stai utilizzando il multi threading).

Alcuni link sulle migliori pratiche qui e qui e qui (probabilmente il miglior articolo di gestione delle eccezioni per .net)

C'è anche una cosa interessante chiamata ELMAH che registrerà eventuali errori ASP.NET che si verifica in un'applicazione Web. So che stai chiedendo una soluzione per app Winform, ma ho pensato che potesse essere utile per chiunque avesse bisogno di questo tipo di cose su un'app Web. Lo usiamo dove lavoro ed è stato molto utile nel debug (specialmente sui server di produzione!)

Ecco alcune delle funzionalità che ha (estratto dalla pagina):

  
      
  • Registrazione di quasi tutte le eccezioni non gestite.
  •   
  • Una pagina Web per visualizzare in remoto l'intero registro delle eccezioni ricodificate.
  •   
  • Una pagina Web per visualizzare in remoto tutti i dettagli di un'eccezione registrata.
  •   
  • In molti casi, puoi rivedere quello schermo giallo della morte originale   ASP.NET generato per un dato   eccezione, anche con la modalità customErrors   spento.
  •   
  • Una notifica via e-mail di ogni errore nel momento in cui si verifica.
  •   
  • Un feed RSS degli ultimi 15 errori dal registro.
  •   
  • Numerose implementazioni di archiviazione di backup per il registro, tra cui   in memoria, Microsoft SQL Server e   diversi hanno contribuito dalla community.
  •   

Puoi monitorare la maggior parte delle eccezioni in quel gestore anche nelle app multithread, ma .NET (a partire da 2.0) non ti consentirà di annullare le eccezioni non gestite a meno che tu non abiliti la modalità di compatibilità 1.1. Quando ciò accade, AppDomain verrà chiuso, qualunque cosa accada. Il meglio che puoi fare è avviare l'app in un AppDomain diverso in modo da poter gestire questa eccezione e creare un nuovo AppDomain per riavviare l'app.

Sto usando il seguente approccio, che funziona e riduce notevolmente la quantità di codice (eppure non sono sicuro che esista un modo migliore o quali potrebbero essere le sue insidie. Ogni volta che chiami: Immagino che le domande che danno svantaggi sarebbero abbastanza educate da chiarire le loro azioni; )

try 
{
    CallTheCodeThatMightThrowException()
 }
catch (Exception ex)
{
    System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace ();
    Utils.ErrorHandler.Trap ( ref objUser, st, ex );
} //eof catch

Ed ecco il codice ErrorHandler: Giusto per chiarire-: objUser - è l'oggetto che modella gli utenti (potresti ottenere informazioni come nome di dominio, dipartimento, regione ecc. Ai fini della registrazione Registratore ILog - è l'oggetto di registrazione - ad es. quello che esegue le attività di registrazione StackTrace st: l'oggetto StackTrace che fornisce informazioni di debug per la tua app

using System;
using log4net; //or another logging platform

namespace GenApp.Utils
{
  public class ErrorHandler
  {
    public static void Trap ( Bo.User objUser, ILog logger, System.Diagnostics.StackTrace st, Exception ex )
    {
      if (ex is NullReferenceException)
      { 
      //do stuff for this ex type
      } //eof if

      if (ex is System.InvalidOperationException) 
      {
        //do stuff for this ex type
      } //eof if

      if (ex is System.IndexOutOfRangeException) 
      {
        //do stuff for this ex type
      } //eof if

      if (ex is System.Data.SqlClient.SqlException)
      {
        //do stuff for this ex type
      } //eof if

      if (ex is System.FormatException)
      {
        //do stuff for this ex type
      } //eof if

      if (ex is Exception)
      {
        //do stuff for this ex type
      } //eof catch

    } //eof method 

  }//eof class 
} //eof namesp

In un'app GUI gestita, per impostazione predefinita, le eccezioni che hanno origine nel thread della GUI sono gestite da qualsiasi cosa sia assegnata a Application.ThreadException.

Le eccezioni che hanno origine negli altri thread sono gestite da AppDomain.CurrentDomain.UnhandledException.

Se vuoi che le eccezioni del tuo thread GUI funzionino esattamente come quelle della tua non-GUI, in modo che vengano gestite da AppDomain.CurrentDomain.UnhandledException, puoi farlo:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);

Un vantaggio nel catturare le eccezioni del thread della GUI usando ThreadException è che puoi offrire all'utente le opzioni per consentire all'app di continuare. Per assicurarti che nessun file di configurazione abbia la precedenza sul comportamento predefinito, puoi chiamare:

Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

Sei ancora vulnerabile alle eccezioni da DLL native mal gestite. Se una DLL nativa installa il proprio gestore tramite Win32 SetUnhandledExceptionFilter, si suppone che salvi il puntatore al filtro precedente e lo chiami anche. In caso contrario, il gestore non verrà chiamato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top