Ich frage mich, was der beste Weg ist, ein "wenn alles andere fehlschlägt, fangen Sie es" zu haben.
Ich meine, Sie behandeln so viele Ausnahmen wie möglich in Ihrer Anwendung, aber es gibt immer noch Fehler. Daher muss ich etwas haben, das alle nicht behandelten Ausnahmen abfängt, damit ich Informationen sammeln und in einer Datenbank speichern oder einreichen kann zu einem Webdienst.
Erfasst das Ereignis AppDomain.CurrentDomain.UnhandledException alles? Auch wenn die Anwendung Multithreading ist?
Randnotiz: Windows Vista stellt native API-Funktionen zur Verfügung, mit denen sich jede Anwendung nach einem Absturz selbst wiederherstellen kann. Ich kann mir den Namen jetzt nicht vorstellen. Ich möchte ihn jedoch lieber nicht verwenden, da viele unserer Benutzer ihn immer noch verwenden Windows XP.
quelle
Antworten:
Ich habe gerade mit AppDomains UnhandledException-Verhalten gespielt (dies ist die letzte Phase, in der die nicht behandelte Ausnahme registriert wird).
Ja, nach der Verarbeitung der Ereignishandler wird Ihre Anwendung beendet und der böse Dialog "... Programm funktioniert nicht mehr" angezeigt.
:) Das kannst du immer noch vermeiden.
Auschecken:
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(); } }
PS Behandeln Sie die für Application.ThreadException (WinForms) oder DispatcherUnhandledException (WPF) nicht behandelten auf der höheren Ebene.
quelle
Thread.CurrentThread.Name = "Dead thread"
.In ASP.NET verwenden Sie die
Application_Error
Funktion in derGlobal.asax
Datei.In WinForms verwenden Sie das
MyApplication_UnhandledException
in derApplicationEvents
DateiDiese beiden Funktionen werden aufgerufen, wenn in Ihrem Code eine nicht behandelte Ausnahme auftritt. Mit diesen Funktionen können Sie die Ausnahme protokollieren und dem Benutzer eine nette Nachricht präsentieren.
quelle
Für Winform-Anwendungen verwende ich neben AppDomain.CurrentDomain.UnhandledException auch Application.ThreadException und Application.SetUnhandledExceptionMode (mit UnhandledExceptionMode.CatchException). Diese Kombination scheint alles zu fangen.
quelle
Im Haupt-Thread haben Sie folgende Optionen:
AppDomain.CurrentDomain.UnhandledException
Application.ThreadException
Application_Error
Für andere Themen:
Beachten Sie, dass diese Ereignisse nicht behandeln Ausnahmen, sie nur berichten sie an die Anwendung - oft , wenn es viel zu spät ist , etwas Sinnvolles / sane über sie zu tun
Das Protokollieren von Ausnahmen ist gut, aber das Überwachen von Anwendungen ist besser ;-)
Vorsichtsmaßnahme: Ich bin der Autor des SafeThread- Artikels.
quelle
Vergessen Sie bei WinForms nicht, auch das nicht behandelte Ausnahmeereignis des aktuellen Threads anzuhängen (insbesondere, wenn Sie Multi-Threading verwenden).
Einige Links zu Best Practices hier und hier und hier (wahrscheinlich der beste Artikel zur Ausnahmebehandlung für .net)
quelle
Es gibt auch eine coole Sache namens ELMAH , die alle ASP.NET-Fehler protokolliert, die in einer Webanwendung auftreten. Ich weiß, dass Sie nach einer Winform App-Lösung fragen, aber ich war der Meinung, dass dies für jeden von Vorteil sein könnte, der solche Dinge in einer Web-App benötigt. Wir verwenden es dort, wo ich arbeite, und es war beim Debuggen sehr hilfreich (insbesondere auf Produktionsservern!)
Hier sind einige Funktionen, die es hat (direkt von der Seite gezogen):
quelle
Sie können die meisten Ausnahmen in diesem Handler auch in Multithread-Apps überwachen. In .NET (beginnend mit 2.0) können Sie jedoch nicht behandelte Ausnahmen nur dann abbrechen, wenn Sie den Kompatibilitätsmodus 1.1 aktivieren. In diesem Fall wird die AppDomain auf jeden Fall heruntergefahren. Das Beste, was Sie tun können, ist, die App in einer anderen AppDomain zu starten, damit Sie diese Ausnahme behandeln und eine neue AppDomain erstellen können, um die App neu zu starten.
quelle
Ich verwende den folgenden Ansatz, der funktioniert und die Menge an Code erheblich reduziert (ich bin mir jedoch nicht sicher, ob es einen besseren Weg gibt oder welche Fallstricke dies haben könnte. Wann immer Sie anrufen: Ich frage, ob die Fragen, die Minuspunkte geben, höflich wären genug, um 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 ErrorHandler-Code: Nur um es klar zu machen: objUser - ist das Objekt, das die Benutzer modelliert (Sie erhalten möglicherweise Informationen wie Domänenname, Abteilung, Region usw. für Protokollierungszwecke ILog Logger - ist das Protokollierungsobjekt - z. B. dasjenige Ausführen der Protokollierungsaktivitäten StackTrace st - Das StackTrace-Objekt, mit dem Sie Debugging-Informationen für Ihre App erhalten
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
quelle
In einer verwalteten GUI-App werden Ausnahmen, die vom GUI-Thread stammen, standardmäßig von allem behandelt, was der Application.ThreadException zugewiesen ist.
Ausnahmen, die von den anderen Threads stammen, werden von AppDomain.CurrentDomain.UnhandledException behandelt.
Wenn Sie möchten, dass Ihre GUI-Thread-Ausnahmen genauso funktionieren wie Ihre Nicht-GUI-Ausnahmen, damit sie von AppDomain.CurrentDomain.UnhandledException behandelt werden, können Sie Folgendes tun:
Ein Vorteil beim Abfangen der GUI-Thread-Ausnahmen mithilfe von ThreadException besteht darin, dass Sie der Verwendung die Optionen geben können, die App fortzusetzen. Um sicherzustellen, dass keine Konfigurationsdateien das Standardverhalten überschreiben, können Sie Folgendes aufrufen:
Sie sind immer noch anfällig für Ausnahmen von schlecht benommenen nativen DLLs. Wenn eine native DLL ihren eigenen Handler mit Win32 SetUnhandledExceptionFilter installiert, soll sie den Zeiger auf den vorherigen Filter speichern und auch aufrufen. Wenn dies nicht der Fall ist, wird Ihr Handler nicht angerufen.
quelle