2010-06-28 11 views
159

Pytanie: Chcę zdefiniować globalną procedurę obsługi wyjątków dla nieobsługiwanych wyjątków w mojej aplikacji konsoli. W ASP.NET, można określić jednym w global.asax, aw oknach aplikacji/usług, można zdefiniować jako poniżejGlobalny program obsługi wyjątków .NET w aplikacji konsoli

AppDomain currentDomain = AppDomain.CurrentDomain; 
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyExceptionHandler); 

Ale jak mogę określić globalną obsługi wyjątku dla aplikacji konsoli?
CurrentDomain wydaje się nie działać (.NET 2.0)?

Edit:

Argh, głupi błąd.
W języku VB.NET należy dodać słowo kluczowe "AddHandler" przed bieżącąDomainą lub nie widać zdarzenia Nieobsługiwanego wyjątku w systemie IntelliSense ...
To dlatego, że kompilatory VB.NET i C# obsługują obsługę zdarzeń różnie.

Odpowiedz

234

Nie, to jest właściwy sposób, aby to zrobić. To działało dokładnie tak jak powinien, coś można pracować może:

using System; 

class Program { 
    static void Main(string[] args) { 
     System.AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper; 
     throw new Exception("Kaboom"); 
    } 

    static void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e) { 
     Console.WriteLine(e.ExceptionObject.ToString()); 
     Console.WriteLine("Press Enter to continue"); 
     Console.ReadLine(); 
     Environment.Exit(1); 
    } 
} 

Czy należy pamiętać, że nie można złapać typu i załadować pliku wyjątki generowane przez jitter ten sposób. Występują przed rozpoczęciem działania metody Main(). Złapanie tych wymaga opóźnienia jittera, przeniesienie ryzykownego kodu na inną metodę i zastosowanie do niego atrybutu [MethodImpl (MethodImplOptions.NoInlining)].

+0

Argh, głupi błąd, muszę dodać AddHandler przed AppDomain.CurrentDomain zobaczyć „UnhandledException” w VB.NET ... –

+2

I wdrożone co zaproponowałeś tutaj, ale nie chcę opuszczać aplikacji. Po prostu chcę go zarejestrować i kontynuować proces (bez 'Console.ReadLine()' lub jakichkolwiek innych zakłóceń w przepływie programu.Jednakże otrzymuję wyjątek ponownie wznosząc się ponownie i znowu, i znowu –

+1

@Shahrooz Jefri: Nie można kontynuować, gdy pojawi się nieobsługiwany wyjątek: Stos jest pomieszany, a to jest terminal.Jeśli masz serwer, to co możesz zrobić w UnhandledExceptionTrapper, to zrestartuj program z tymi samymi argumentami wiersza poleceń: –

-7

To, co próbujesz, powinno działać zgodnie z dokumentami MSDN dla .Net 2.0. Możesz również spróbować wypróbować/złapać w prawo wokół punktu wejścia do aplikacji konsolowej.

static void Main(string[] args) 
{ 
    try 
    { 
     // Start Working 
    } 
    catch (Exception ex) 
    { 
     // Output/Log Exception 
    } 
    finally 
    { 
     // Clean Up If Needed 
    } 
} 

A teraz twój haczyk obsłuży nic nie złapał (w głównym wątku). Może to być pełne wdzięku, a nawet ponowne uruchomienie w miejscu, w którym się znajduje, lub po prostu pozwolić aplikacji umrzeć i zarejestrować wyjątek. Dodajesz wreszcie, jeśli chcesz zrobić porządek. Każdy wątek będzie wymagał obsługi wyjątków wysokiego poziomu, podobnych do głównej.

Edytowany w celu wyjaśnienia kwestii dotyczących wątków wskazanych przez BlueMonkMN i szczegółowo przedstawiony w jego odpowiedzi.

+1

Niestety, wyjątki nadal mogą być wyrzucane poza blok główny(). To nie jest tak naprawdę "catch all", jak mogłoby się wydawać. Zobacz odpowiedź @Hans. –

+0

@Mike Najpierw powiedziałem, że sposób, w jaki to robi jest poprawny, i że może spróbować spróbować/złapać w głównej. Nie wiem, dlaczego ty (lub ktoś inny) oddał mi głos, gdy zgodziłem się z Hansem, udzielając innej odpowiedzi, której nie oczekiwałam. To naprawdę nie jest sprawiedliwe, a następnie powiedzieć, że alternatywa jest błędna, nie dostarczając żadnego dowodu na to, w jaki sposób wyjątek, który może zostać przechwycony przez proces AppDomain UnhandledException, którego próbka/catch w Main nie może złapać.Uważam za niegrzeczne stwierdzenie, że coś jest nie tak, bez udowodnienia, dlaczego jest to złe, po prostu mówiąc, że tak jest, nie czyni tego tak. –

+0

To dość oczywiste, że właśnie przegłosowałeś 4 moje stare posty z 2009 roku w odwecie. Rozważ edytowanie swojego wpisu, a ja cofnę moje zeznania (i powinieneś cofnąć swoje wściekłe pomyłki, które mi dałeś, zrobię to samo). –

9

Należy również obsługiwać wyjątki od wątków:

static void Main(string[] args) { 
Application.ThreadException += MYThreadHandler; 
} 

private void MYThreadHandler(object sender, Threading.ThreadExceptionEventArgs e) 
{ 
    Console.WriteLine(e.Exception.StackTrace); 
} 

Whoop, przepraszam, że był dla WinForms, żadnych wątków jesteś korzystających z aplikacji konsoli trzeba będzie ująć w try/catch blok. Nić w tle, która napotkała nieobsługiwane wyjątki, nie powoduje zakończenia działania aplikacji.

20

Jeśli masz aplikację z jednym gwintem, możesz użyć prostej funkcji prób/catch w funkcji głównej, jednak nie obejmuje ona wyjątków, które mogą być wyrzucane poza główną funkcję, na innych wątkach, na przykład (jak zauważono w innych komentarzach).Ten kod demonstruje, w jaki sposób wyjątek może spowodować zakończenie działania aplikacji, nawet jeśli próbowałeś obsłużyć ją w Main (zwróć uwagę, jak program kończy pracę z wdziękiem, jeśli naciśniesz klawisz enter i zezwolisz aplikacji na zakończenie z rozwagą przed wystąpieniem wyjątku, ale jeśli pozwolisz jej działać , to kończy się dość nieszczęśliwie):

static bool exiting = false; 

static void Main(string[] args) 
{ 
    try 
    { 
     System.Threading.Thread demo = new System.Threading.Thread(DemoThread); 
     demo.Start(); 
     Console.ReadLine(); 
     exiting = true; 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("Caught an exception"); 
    } 
} 

static void DemoThread() 
{ 
    for(int i = 5; i >= 0; i--) 
    { 
     Console.Write("24/{0} =", i); 
     Console.Out.Flush(); 
     Console.WriteLine("{0}", 24/i); 
     System.Threading.Thread.Sleep(1000); 
     if (exiting) return; 
    } 
} 

Możesz otrzymywać powiadomienia, gdy inny wątek zgłasza wyjątek, aby wykonać niektóre oczyścić przed zakończeniem aplikacji, ale o ile wiem, nie można, od aplikacji konsoli , wymuś kontynuację działania aplikacji, jeśli nie potraktujesz wyjątku w wątku, z którego jest on wysyłany, bez użycia pewnych niejasnych opcji zgodności, aby aplikacja zachowywała się tak, jak w przypadku .NET 1.x. Ten kod demonstruje jak główny wątek może zostać powiadomiony wyjątków pochodzących z innych wątków, ale nadal będą zakończyć nieszczęśliwie:

static bool exiting = false; 

static void Main(string[] args) 
{ 
    try 
    { 
     System.Threading.Thread demo = new System.Threading.Thread(DemoThread); 
     AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); 
     demo.Start(); 
     Console.ReadLine(); 
     exiting = true; 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("Caught an exception"); 
    } 
} 

static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 
{ 
    Console.WriteLine("Notified of a thread exception... application is terminating."); 
} 

static void DemoThread() 
{ 
    for(int i = 5; i >= 0; i--) 
    { 
     Console.Write("24/{0} =", i); 
     Console.Out.Flush(); 
     Console.WriteLine("{0}", 24/i); 
     System.Threading.Thread.Sleep(1000); 
     if (exiting) return; 
    } 
} 

Więc moim zdaniem, najczystszy sposób obsłużyć go w aplikacji konsoli jest zapewnienie że każdy wątek ma obsługi wyjątku na poziomie root:

static bool exiting = false; 

static void Main(string[] args) 
{ 
    try 
    { 
     System.Threading.Thread demo = new System.Threading.Thread(DemoThread); 
     demo.Start(); 
     Console.ReadLine(); 
     exiting = true; 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("Caught an exception"); 
    } 
} 

static void DemoThread() 
{ 
    try 
    { 
     for (int i = 5; i >= 0; i--) 
     { 
     Console.Write("24/{0} =", i); 
     Console.Out.Flush(); 
     Console.WriteLine("{0}", 24/i); 
     System.Threading.Thread.Sleep(1000); 
     if (exiting) return; 
     } 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("Caught an exception on the other thread"); 
    } 
} 
+0

TRY CATCH nie działa w trybie zwolnienia w przypadku nieoczekiwanych błędów: / – Muflix

Powiązane problemy