.NET - Was ist der beste Weg, ein „fangen alle Ausnahmen-Handler“ zu implementieren
-
03-07-2019 - |
Frage
Ich frage mich, was der beste Weg, eine zu haben ist „wenn alle Stricke es nicht fangen“.
Ich meine, dich Umgang mit Ihnen so viele Ausnahmen wie möglich in Ihrer Anwendung, aber immer noch gibt es zwangsläufig Fehler sein, also muss ich etwas haben, das fängt alle unbehandelte Ausnahmen, so kann ich Informationen und Laden sammeln sie in einer Datenbank oder legt sie auf einem Web-Service.
Hat das AppDomain.CurrentDomain.UnhandledException Ereignis alles erfassen? Selbst wenn die Anwendung ist multithreaded?
Side Hinweis: Windows Vista macht native API-Funktionen, die für jede Anwendung ermöglichen erholen sich nach einem Absturz ... kann jetzt nicht denken Sie an den Namen ... aber ich möchte lieber nicht verwenden Sie es, so viele unserer Nutzer noch mit Windows XP.
Lösung
Ich habe gerade mit AppDomain des UnhandledException Verhalten gespielt, (Dies ist die letzte Stufe der nicht behandelte Ausnahme bei registriert ist)
Ja, nach der Verarbeitung der Event-Handler Ihre Anwendung beendet wird und die fiesen „... Programm aufgehört zu arbeiten Dialog“ gezeigt.
:) Sie noch kann man erkennen, vermeiden.
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. handhaben Sie das nicht behandelte für Application.ThreadException (WinForms) oder DispatcherUnhandledException (WPF) auf der höheren Ebene.
Andere Tipps
In ASP.NET, verwenden Sie die Application_Error
Funktion in der Global.asax
Datei.
In WinForms, verwenden Sie die MyApplication_UnhandledException
in der ApplicationEvents
Datei
sind Beiden Funktionen aufgerufen, wenn eine nicht behandelte Ausnahme in Ihrem Code auftritt. Sie können die Ausnahme anmelden und eine nette Nachricht aus diesen Funktionen für den Benutzer darstellen.
Für Winform-Anwendungen, zusätzlich zu AppDomain.CurrentDomain.UnhandledException Ich benutze auch Application.ThreadException und Application.SetUnhandledExceptionMode (w / UnhandledExceptionMode.CatchException). Diese Kombination scheint alles zu fangen.
Auf dem Haupt-Thread, haben Sie folgende Möglichkeiten:
- Console oder Service-Anwendung:
AppDomain.CurrentDomain.UnhandledException
- WinForms-Anwendung:
Application.ThreadException
- Web-Anwendung: Global.asax des
Application_Error
Für andere Themen:
- Sekundär Threads haben keine unhandled-Ausnahmen; verwenden SafeThread
- Worker-Threads: (Timer, Threadpool) gibt es überhaupt kein Sicherheitsnetz
Beachten Sie, dass diese Ereignisse nicht behandeln Ausnahmen, sie nur sie an die Anwendung - oft, wenn es viel zu spät ist, etwas zu tun nützlich / sane über sie
Protokollierung Ausnahmen sind gut, aber Monitoring-Anwendungen sind besser; -)
Caveat. Ich bin der Autor des SafeThread Artikel
Für WinForms, vergessen Sie nicht, auch auf den aktuellen Thread nicht behandelte Ausnahmeereignis zu befestigen (vor allem, wenn Sie Multi-Threading verwenden).
Einige Links auf Best Practices hier und hier und hier (wahrscheinlich der beste Ausnahmebehandlung Artikel für .net)
Es gibt auch eine coole Sache namens ELMAH , die alle ASP.NET-Fehler protokolliert, dass tritt in einer Web-Anwendung. Ich weiß, Sie fragen, um eine Winform App Lösung, aber ich fühlte dies von Vorteil für jeden, könnte diese Art der Sache auf einer Web-App zu benötigen. Wir verwenden es, wo ich arbeite und es war in dem Debuggen sehr hilfreich (vor allem auf Produktionsservern!)
Hier einige Features, die es (zog sich direkt an der Seite) hat:
- Protokollierung von fast allen unbehandelten Ausnahmen.
- Eine Web-Seite aus der Ferne das gesamte Protokoll von umcodiert Ausnahmen anzuzeigen.
- Eine Webseite aus der Ferne die vollständigen Details von einem protokollierten Ausnahme anzuzeigen.
- In vielen Fällen können Sie den ursprünglichen gelben Schirm des Todes überprüfen, die ASP.NET erzeugt für einen bestimmten Ausnahme, auch mit Custom Modus ausgeschaltet.
- Eine E-Mail-Benachrichtigung über jeden Fehler zu der Zeit sie auftritt.
- Ein RSS-Feed der letzten 15 Fehler aus dem Protokoll.
- Eine Reihe von Sicherungsspeicher-Implementierungen für das Protokoll, einschließlich In-Memory, Microsoft SQL Server und mehrere von der Gemeinschaft beigetragen hat.
Sie können die meisten Ausnahmen in diesem Handler auch in Multi-Thread-Anwendungen überwachen, aber .NET (mit 2.0 Start) werden Sie Ausnahmen aufheben unhandled nicht zulassen, wenn Sie den 1.1-Kompatibilitätsmodus zu aktivieren. Wenn das der AppDomain passiert wird, egal heruntergefahren, was. Das Beste, was Sie tun können, ist die App in einem anderen AppDomain zu starten, so dass Sie diese Ausnahme behandeln kann und eine neue AppDomain erstellen die App neu zu starten.
Ich bin mit dem folgenden Ansatz, der funktioniert und verringert die Menge an Code (aber ich bin nicht sicher, ob es ein besserer Weg ist oder was die Gefahren den sie sein könnten. Wann immer du anrufst: Ich quess die quys minuse gibt genug wäre höflich ihre Handlungen zu klären; )
try
{
CallTheCodeThatMightThrowException()
}
catch (Exception ex)
{
System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace ();
Utils.ErrorHandler.Trap ( ref objUser, st, ex );
} //eof catch
Und hier ist der Fehlerbehandler Code: Nur um Klar-: objUser - ist das Objekt, die appusers Modellierung (Sie Informationen, wie zB Domain-Namen könnten, Abteilung, Region usw. zur Protokollierung ILog Logger - ist das Objekt Protokollierung - z derjenige, der die Protokollierung Aktivitäten durchführen Stacktrace st - das Objekt Stacktrace geben Sie info Debuggen für Ihre 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 einer manged GUI-Anwendung, die standardmäßig Ausnahmen, die in dem GUI-Thread stammen, werden behandelt, indem alles, was mit dem Application.ThreadException zugeordnet ist.
Ausnahmen, die in den anderen Threads stammen, werden durch AppDomain.CurrentDomain.UnhandledException behandelt.
Wenn Sie Ihr GUI-Thread Ausnahmen wollen wie Ihr-non-GUI diejenigen arbeiten, so dass sie von AppDomain.CurrentDomain.UnhandledException behandelt bekommen, können Sie dies tun:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
Ein Vorteil der GUI-Thread Ausnahmen zu fangen Thread ist, dass Sie die Verwendung der Optionen zu lassen, die App weiter geben kann. Um sicherzustellen, dass keine Konfigurationsdateien Standardverhalten überschreiben, können Sie anrufen:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Sie sind immer noch anfällig für Ausnahmen von schlecht benommen nativer DLLs. Wenn eine native DLL einen eigenen Handler Win32 SetUnhandledExceptionFilter installiert wird angenommen, den Zeiger auf den vorherigen Filter zu speichern und sie nennen. Wenn es nicht so tut, Handler wird nicht‘aufgerufen.