c# - thread - wpf throw unhandled exception




Ausnahmen global in einer WPF-Anwendung abfangen? (4)

Beachten Sie außerdem, was andere hier erwähnt haben, dass die Application.DispatcherUnhandledException (und ihre Ähnlichkeiten ) mit kombiniert werden

<configuration>
  <runtime>  
    <legacyUnhandledExceptionPolicy enabled="1"/>
  </runtime>
</configuration>

In der app.config wird verhindert, dass die sekundäre Thread-Ausnahme die Anwendung herunterfährt.

Wir haben eine WPF-Anwendung, bei der Teile davon zur Laufzeit Ausnahmen auslösen können. Ich möchte alle nicht behandelten Ausnahmen global abfangen und sie protokollieren, ansonsten aber die Programmausführung so fortsetzen, als ob nichts passiert wäre (ähnlich wie VB's On Error Resume Next ).

Ist das in C # möglich? Und wenn ja, wo genau müsste ich den Ausnahmebehandlungscode setzen?

Momentan kann ich keinen einzelnen Punkt sehen, an dem ich einen try / catch umschließen könnte und der alle möglichen Ausnahmen erfassen würde. Und selbst dann hätte ich wegen des Fangs alles zurückgelassen, was ausgeführt wurde. Oder denke ich hier in schrecklich falsche Richtungen?

ETA: Weil viele Leute unten darauf hingewiesen haben: Die Anwendung ist nicht für die Kontrolle von Kernkraftwerken. Wenn es abstürzt, ist es nicht so eine große Sache, aber zufällige Ausnahmen, die hauptsächlich UI-bezogen sind, sind ein Ärgernis in dem Kontext, in dem es verwendet würde. Es gab (und wahrscheinlich immer noch) einige davon und da es eine Plugin-Architektur verwendet und von anderen erweitert werden kann (auch Studenten in diesem Fall; also keine erfahrenen Entwickler, die völlig fehlerfreien Code schreiben können).

Was die Ausnahmen betrifft, die gefangen werden: Ich protokolliere sie in einer Protokolldatei, einschließlich der kompletten Stack-Trace. Das war der springende Punkt dieser Übung. Nur um den Leuten zu begegnen, die meine Analogie zu VBs OERN zu wörtlich genommen haben.

Ich weiß, dass das blinde Ignorieren bestimmter Fehlerklassen gefährlich ist und meine Anwendungsinstanz möglicherweise beschädigt. Wie bereits gesagt, ist dieses Programm für niemanden unternehmenskritisch. Niemand in ihrem Verstand würde das Überleben der menschlichen Zivilisation darauf wagen. Es ist einfach ein kleines Werkzeug, um bestimmte Design-Ansätze zu testen. Softwareentwicklung.

Für die sofortige Verwendung der Anwendung gibt es nicht viele Dinge, die bei einer Ausnahme passieren können:

  • Keine Ausnahmebehandlung - Fehlerdialog und Anwendungsexit. Das Experiment muss wiederholt werden, obwohl wahrscheinlich mit einem anderen Thema. Es wurden keine Fehler protokolliert, was bedauerlich ist.
  • Generische Ausnahmebehandlung - gutartiger Fehler, kein Schaden angerichtet. Dies sollte der allgemeine Fall sein, der von allen Fehlern beurteilt wird, die wir während der Entwicklung beobachten konnten. Das Ignorieren dieser Art von Fehlern sollte keine unmittelbaren Konsequenzen haben; Die Kerndatenstrukturen sind so gut getestet, dass sie das problemlos überstehen.
  • Generische Ausnahmebehandlung - schwerwiegender Fehler eingeschlossen, möglicherweise später Absturz. Dies kann selten passieren. Wir haben es noch nie gesehen. Der Fehler wird trotzdem protokolliert und ein Absturz könnte unvermeidlich sein. Das ist konzeptionell dem ersten Fall ähnlich. Außer dass wir einen Stack-Trace haben. Und in den meisten Fällen wird der Benutzer dies nicht bemerken.

Was die vom Programm erzeugten Versuchsdaten angeht: Ein schwerwiegender Fehler würde im schlimmsten Fall dazu führen, dass keine Daten aufgezeichnet werden. Subtile Veränderungen, die das Ergebnis des Experiments geringfügig verändern, sind eher unwahrscheinlich. Und selbst in diesem Fall, wenn die Ergebnisse zweifelhaft erscheinen, wurde der Fehler protokolliert; Man kann diesen Datenpunkt immer noch wegwerfen, wenn es ein totaler Ausreißer ist.

Zusammenfassend: Ja, ich betrachte mich immer noch zumindest teilweise als vernünftig und halte keine globale Ausnahmehandhabungsroutine für notwendig, die das Programm dazu bringt, notwendigerweise total böse zu sein. Wie bereits zweimal erwähnt, kann eine solche Entscheidung je nach Anwendung gültig sein. In diesem Fall wurde es als eine gültige Entscheidung beurteilt und nicht totaler Schwachsinn. Für jede andere Anwendung könnte diese Entscheidung anders aussehen. Aber bitte beschuldige mich oder die anderen Leute, die an diesem Projekt gearbeitet haben, nicht, die Welt zu explodieren, nur weil wir Fehler ignorieren.

Randnotiz: Es gibt genau einen Benutzer für diese Anwendung. Es ist nicht so etwas wie Windows oder Office, das von Millionen genutzt wird, wo die Kosten für das Auslösen von Ausnahmen für den Benutzer überhaupt erst sehr unterschiedlich wären.


Beispielcode, der NLog verwendet , der Ausnahmen abfängt , die von allen Threads in der Anwendungsdomäne , vom UI-Dispatcher-Thread und von den asynchronen Funktionen ausgelöst werden :

App.xaml.cs:

public partial class App : Application
{
    private static Logger _logger = LogManager.GetCurrentClassLogger();

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        SetupExceptionHandling();
    }

    private void SetupExceptionHandling()
    {
        AppDomain.CurrentDomain.UnhandledException += (s, e) =>
            LogUnhandledException((Exception)e.ExceptionObject, "AppDomain.CurrentDomain.UnhandledException");

        DispatcherUnhandledException += (s, e) =>
            LogUnhandledException(e.Exception, "Application.Current.DispatcherUnhandledException");

        TaskScheduler.UnobservedTaskException += (s, e) =>
            LogUnhandledException(e.Exception, "TaskScheduler.UnobservedTaskException");
    }

    private void LogUnhandledException(Exception exception, string source)
    {
        string message = $"Unhandled exception ({source})";
        try
        {
            System.Reflection.AssemblyName assemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName();
            message = string.Format("Unhandled exception in {0} v{1}", assemblyName.Name, assemblyName.Version);
        }
        catch (Exception ex)
        {
            _logger.Error(ex, "Exception in LogUnhandledException");
        }
        finally
        {
            _logger.Error(exception, message);
        }
    }

Verwenden Sie das Application.DispatcherUnhandledException Event . Siehe diese Frage für eine Zusammenfassung (siehe Drew Noakes Antwort ).

Beachten Sie, dass es immer noch Ausnahmen geben wird, die eine erfolgreiche Wiederaufnahme Ihrer Anwendung verhindern, z. B. nach einem Stapelüberlauf, erschöpftem Speicher oder verlorener Netzwerkverbindung, während Sie versuchen, in der Datenbank zu speichern.


Wie "VB's On Error Resume Next?" Das klingt irgendwie gruselig. Erste Empfehlung ist es nicht tun. Zweite Empfehlung ist es nicht tun und nicht darüber nachdenken. Sie müssen Ihre Fehler besser isolieren. Wie man dieses Problem angehen kann, hängt davon ab, wie der Code strukturiert ist. Wenn Sie ein Muster wie MVC oder ähnliches verwenden, sollte dies nicht zu schwierig sein und würde definitiv keinen globalen Ausnahme-Schlucker benötigen. Zweitens, suchen Sie nach einer guten Logging-Bibliothek wie log4net oder verwenden Sie Tracing. Wir müssen mehr Details wissen, über welche Arten von Ausnahmen Sie sprechen und welche Teile Ihrer Anwendung dazu führen können, dass Ausnahmen ausgelöst werden.





exception-handling