Globalnie łapiesz wyjątki w aplikacji WPF?

Mamy aplikację WPF, gdzie jej części mogą wyrzucać wyjątki w czasie wykonywania. Chciałbym globalnie złapać dowolny nieobsługiwany wyjątek i zalogować je, ale poza tym kontynuować wykonywanie programu tak, jakby nic się nie stało(trochę jak VB On Error Resume Next).

Czy jest to możliwe w C#? A jeśli tak, to gdzie dokładnie powinienem umieścić kod obsługi wyjątków?

Obecnie nie widzę żadnego punktu, w którym mógłbym zawinąć try/catch wokół i które wyłapałyby wszystkie wyjątki, które mogłyby występuje. I nawet wtedy zostawiłbym to, co zostało stracone z powodu połowu. A może myślę w bardzo złym kierunku?

ETA: ponieważ wiele osób poniżej wskazało na to: aplikacja nie służy do kontrolowania elektrowni jądrowych. Jeśli ulegnie awarii, nie jest to wielka sprawa, ale przypadkowe wyjątki, które są głównie związane z interfejsem użytkownika, są uciążliwe w kontekście, w którym zostanie użyty. Było (i prawdopodobnie nadal są) kilka z nich, a ponieważ korzysta z wtyczki architektury i mogą być rozszerzane przez innych (również studentów w tym przypadku; więc Nie doświadczonych programistów, którzy są w stanie napisać całkowicie wolny od błędów kod).

Jeśli chodzi o wyjątki, które zostają złapane: zapisuję je do pliku dziennika, łącznie z kompletnym śladem stosu. O to chodziło w tym ćwiczeniu. Żeby przeciwstawić się tym ludziom, którzy brali moją analogię do OERN VB zbyt dosłownie.

Wiem, że ślepe ignorowanie pewnych klas błędów jest niebezpieczne i może uszkodzić moją instancję aplikacji. Jak wspomniano wcześniej, ten program nie jest krytyczny dla nikogo. Nikt przy zdrowych zmysłach nie postawiłby na przetrwanie ludzkiej cywilizacji. To po prostu małe narzędzie do testowania pewnych podejść projektowych wrt. Inżynieria oprogramowania.

Do natychmiastowego użycia aplikacji nie ma wielu rzeczy, które mogą się zdarzyć na wyjątku:

  • Brak obsługi wyjątków-okno dialogowe błędu i wyjście aplikacji. Eksperyment trzeba jednak powtórzyć prawdopodobnie z innym tematem. Nie zarejestrowano żadnych błędów, co jest niefortunne.
  • Ogólna obsługa wyjątków-łagodny błąd uwięziony, żadna krzywda. Powinien to być powszechny przypadek oceniany na podstawie wszystkich błędów, które widzieliśmy podczas opracowywania. Ignorowanie tego rodzaju błędów nie powinno mieć natychmiastowych konsekwencji; podstawowe struktury danych są testowane na tyle dobrze, że z łatwością to przetrwają.
  • Ogólna obsługa wyjątków-poważny błąd uwięziony, prawdopodobnie awaria w późniejszym momencie. To może się zdarzyć rzadko. Do tej pory go nie widzieliśmy. Błąd jest rejestrowany i awaria może być nieunikniona. Jest to więc koncepcyjnie podobne do pierwszego przypadku. Poza tym, że mamy ślad stosu. A w większości przypadków użytkownik nawet nie zauważy.

Jeśli chodzi o dane eksperymentu generowane przez program: poważny błąd w najgorszym wypadku spowodowałby, że żadne dane nie zostaną zapisane. Subtelne zmiany, które tak nieznacznie zmieniają wynik eksperymentu, są dość mało prawdopodobne. A nawet w w takim przypadku, jeśli wyniki wydają się wątpliwe, błąd został zarejestrowany; nadal można wyrzucić ten punkt danych, jeśli jest to całkowita wartość odstająca.

PodsumowujÄ ... c: tak, uwaĺźam, Ĺźe nadal przynajmniej czÄ ™ Ĺ "ciowo zachowujÄ ™ siÄ ™ przy zdrowych zmysĹ' ach i nie uwaĺźam, Ĺźe globalna procedura obsĹ 'ugi wyjÄ ... tkĂłw pozostawia uruchomiony program za absolutnie zĹ' Ä.... Jak już wspomniano dwa razy wcześniej, taka decyzja może być ważna, w zależności od wniosku. W tym przypadku została uznana za słuszną decyzję, a nie całkowitą i kompletną bzdurę. dla każdy inny wniosek, że decyzja może wyglądać inaczej.Ale proszę, nie oskarżaj mnie ani innych ludzi, którzy pracowali nad tym projektem, aby potencjalnie wysadzić świat tylko dlatego, że ignorujemy błędy.

Uwaga na marginesie: jest dokładnie jeden użytkownik dla tej aplikacji. To nie jest coś takiego jak Windows lub Office, który jest używany przez miliony, gdzie koszt posiadania wyjątków dla użytkownika w ogóle byłby bardzo różny w pierwszej kolejności.

Author: Lars Truijens, 2009-04-27

6 answers

Użyj Application.DispatcherUnhandledException Event. Zobacz to pytanie dla podsumowania (zobacz narysował odpowiedź Noakesa).

Pamiętaj, że nadal istnieją wyjątki, które wykluczają pomyślne wznowienie aplikacji, np. po przepełnieniu stosu, wyczerpaniu pamięci lub utracie łączności sieciowej podczas próby zapisania do bazy danych.

 162
Author: David Schmitt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:23

AppDomain.UnhandledException Event

To zdarzenie dostarcza powiadomienia o nieprzewidzianych wyjątkach. Pozwala na aplikacja do logowania informacji o wyjątku przed systemem domyślna obsługa zgłasza wyjątek użytkownikowi i kończy podanie.

   public App()
   {
      AppDomain currentDomain = AppDomain.CurrentDomain;
      currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);    
   }

   static void MyHandler(object sender, UnhandledExceptionEventArgs args) 
   {
      Exception e = (Exception) args.ExceptionObject;
      Console.WriteLine("MyHandler caught : " + e.Message);
      Console.WriteLine("Runtime terminating: {0}", args.IsTerminating);
   }

Jeśli zdarzenie UnhandledException jest obsługiwane w domyślnej aplikacji domeny, jest tam podniesiona dla każdego nieobsługiwanego wyjątku w dowolnym wątku, bez względu na wszystko domena aplikacji, w której rozpoczął się wątek. Jeśli wątek uruchomiony w domenie aplikacji, która ma obsługę zdarzeń dla UnhandledException, zdarzenie jest wywoływane w tej domenie aplikacji. Jeśli ta domena aplikacji nie jest domeną domyślną aplikacji, oraz istnieje również obsługa zdarzeń w domyślnej domenie aplikacji, zdarzenie jest wywoływane w obu domenach aplikacji.

Na przykład, załóżmy, że wątek rozpoczyna się w domenie aplikacji " AD1", wywołuje metodę w aplikacji domeny "AD2", a stamtąd wywołuje metoda w domenie aplikacji "AD3", gdzie rzuca wyjątek. Na pierwsza domena aplikacji, w której Zdarzenie UnhandledException może być podniesiony jest "AD1". Jeśli ta domena aplikacji nie jest domyślna domeny aplikacji, zdarzenie może być również wywołane w domyślnej domena aplikacji.

 26
Author: CharithJ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-27 00:29:23

Oprócz tego, co inni tu wspominali, zauważ, że łączenie Application.DispatcherUnhandledException (i jego podobieństw ) z

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

W app.config zapobiegnie wyłączeniu aplikacji przez dodatkowy wyjątek wątków.

 17
Author: Hertzel Guinness,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-28 16:30:13

Przykładowy kod wykorzystujący NLog, który wychwytuje wyjątki wyrzucane z wszystkich wątków w AppDomain , z UI dispatcher thread oraz z async functions :

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);
        }
    }
 14
Author: Hüseyin Yağlı,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-18 07:19:19

Oto kompletny przykład użycia NLog

using NLog;
using System;
using System.Windows;

namespace MyApp
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        private static Logger logger = LogManager.GetCurrentClassLogger();

        public App()
        {
            var currentDomain = AppDomain.CurrentDomain;
            currentDomain.UnhandledException += CurrentDomain_UnhandledException;
        }

        private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            var ex = (Exception)e.ExceptionObject;
            logger.Error("UnhandledException caught : " + ex.Message);
            logger.Error("UnhandledException StackTrace : " + ex.StackTrace);
            logger.Fatal("Runtime terminating: {0}", e.IsTerminating);
        }        
    }


}
 1
Author: Academy of Programmer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-03 12:09:45

Jak " VB ' s On Error Resume Next?"To brzmi trochę przerażająco. Pierwsza rekomendacja to nie rób tego. Druga rekomendacja to nie rób tego i nie myśl o tym. Musisz lepiej wyizolować swoje wady. Jeśli chodzi o podejście do tego problemu, zależy to od struktury kodu. Jeśli używasz wzorca takiego jak MVC lub tym podobne, to nie powinno to być zbyt trudne i na pewno nie wymagałoby globalnego wyjątku. Po drugie, poszukaj dobrej biblioteki logowania, takiej jak log4net lub użyj namierzam. Musimy wiedzieć więcej szczegółów, takich jak rodzaje WYJĄTKÓW, o których mówisz i jakie części aplikacji mogą skutkować wyrzuceniem WYJĄTKÓW.

 -3
Author: BobbyShaftoe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-27 11:25:25