Zentraler ExceptionHandler für unbehandelte Exceptions

Thomas Darimont

Erfahrenes Mitglied
Hallo,

C#:
using System;
using System.Collections.Generic;
using System.Text;

namespace De.Tutorials.Training
{
    public class GenericExceptionHandlerExample
    {
        public static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(delegate(object o, UnhandledExceptionEventArgs eventArgs)
            {
                Console.WriteLine("bubu: " + o + " Exception: " + eventArgs.ExceptionObject);
                
            });
            Operation1();
        }

        private static void Operation1()
        {
            Operation2();
        }

        private static void Operation2()
        {
            throw new Exception("The method or operation is not implemented.");
        }
    }
}

Ausgabe:
Code:
bubu: Name:De.Tutorials.Training.exe
Keine Kontextrichtlinien vorhanden.
 Exception: System.Exception: The method or operation is not implemented.
   bei De.Tutorials.Training.GenericExceptionHandlerExample.Operation2() in C:\Dokumente und Einstellungen\Tom\Eigene Dateien\Visual Studio 2005\Projects\De.Tutorials.Training\De.Tutorials.Training\GenericExceptionHandlerExample.cs:Zeile 26.
   bei De.Tutorials.Training.GenericExceptionHandlerExample.Main(String[] args) in C:\Dokumente und Einstellungen\Tom\Eigene Dateien\Visual Studio 2005\Projects\De.Tutorials.Training\De.Tutorials.Training\GenericExceptionHandlerExample.cs:Zeile 16.

Unbehandelte Ausnahme: System.Exception: The method or operation is not implemented.
   bei De.Tutorials.Training.GenericExceptionHandlerExample.Operation2() in C:\Dokumente und Einstellungen\Tom\Eigene Dateien\Visual Studio 2005\Projects\De.Tutorials.Training\De.Tutorials.Training\GenericExceptionHandlerExample.cs:Zeile 26.
   bei De.Tutorials.Training.GenericExceptionHandlerExample.Main(String[] args) in C:\Dokumente und Einstellungen\Tom\Eigene Dateien\Visual Studio 2005\Projects\De.Tutorials.Training\De.Tutorials.Training\GenericExceptionHandlerExample.cs:Zeile 16.
Drücken Sie eine beliebige Taste . . .

Über diesen Weg kann man dann an zentraler Stelle auf unbehandelte Exceptions reagieren.

Gruß Tom
 
Das ist so nicht richtig bzw. nicht vollständig.

Unter .NET gibt es unterschiedliche Arten von Exceptions. Bei einigen von SystemException abgeleiteten Ausnahmen (Ableitungen) funktioniert dein Beispiel nur bedingt. Einige Exceptions (NotImplementedException - die hättest du in deinem Beispiel der Sauberkeit halber verwenden sollen) werden durch dein Beispiel zwar aufgegangen, die Anwendung wird aber dennoch beendet.

Bei einer StackOverflowException wird die Anwendung SOFORT beendet. Das heißt, dass deine Variante nicht einmal ansatzweise anschlägt (ab 2.0).

Zudem ist diese Variante NICHT als Handler gedacht, sondern lediglich zu "Dokumentationszwecken" (siehe Logging) bzw. um einen aktuellen Anwendungsstatus zu speichern, bevor die Anwendung selbst über den Jordan geht.
 
Hallo,

Bei einer StackOverflowException wird die Anwendung SOFORT beendet. Das heißt, dass deine Variante nicht einmal ansatzweise anschlägt (ab 2.0).
Console.WriteLine(Environment.Version.ToString()); sagt bei mir: 2.0.50727.42

Also wenn ich om obigen Beispiel eine StackOverFlowException (was übrigens eine SystemException ist) werfe, so wird der Handler doch angesprungen, aber vielleicht befindet sich meine CLR ja in einer anderen Dimension als deine und verhält sich dementsprechend auch anders ;-)

C#:
...
 private static void Operation2()
        {
            Console.WriteLine("xxx");
            throw new StackOverflowException("oh oh");
        }
...

Ausgabe:
Code:
xxx
bubu: Name:De.Tutorials.Training.exe
Keine Kontextrichtlinien vorhanden.
 Exception: System.StackOverflowException: oh oh
   bei De.Tutorials.Training.GenericExceptionHandlerExample.Operation2() in C:\Dokumente und Einstellungen\Tom\Eigene Dateien\Visual Studio 2005\Projects\De.Tutorials.Training\De.Tutorials.Training\GenericExceptionHandlerExample.cs:Zeile 35.
   bei De.Tutorials.Training.GenericExceptionHandlerExample.Main(String[] args) in C:\Dokumente und Einstellungen\Tom\Eigene Dateien\Visual Studio 2005\Projects\De.Tutorials.Training\De.Tutorials.Training\GenericExceptionHandlerExample.cs:Zeile 24.

Unbehandelte Ausnahme: System.StackOverflowException: oh oh
   bei De.Tutorials.Training.GenericExceptionHandlerExample.<Main>b__0(Object o, UnhandledExceptionEventArgs eventArgs) in C:\Dokumente und Einstellungen\Tom\Eigene Dateien\Visual Studio 2005\Projects\De.Tutorials.Training\De.Tutorials.Training\GenericExceptionHandlerExample.cs:Zeile 17.
Drücken Sie eine beliebige Taste . . .

Außerdem sollte aus der Ausgabe auch deutlich werden, das die Exception nicht "behandelt" sondern einfach nur "Protokolliert" wird. "Aufhalten" kann man mit diesem UnhandledExceptionEventHandler keine Exceptions mehr. Da hast du vollkommen recht, aber das hat man ja auch an der Beispielausgabe gesehen (ich schrieb deshalb ja auch "reagieren" und nicht "behandeln" ;-) Ich geb zu den Namen des Beispiels hab ich schlecht gewählt.

Gruß Tom
 
Gleiche Version, allerdings unterschiedlicher Test:

Eigene Klasse mit einer Eigenschaft, welche im Setter auf die Eigenschaft und nicht auf den privaten Member verweist. Klassischer Fall eines Stackoverflows. Dabei kommt es zu keiner Ausgabe.

<sarcasm>Thema "reagieren": Vermutlich definieren wir das Wort unterschiedlich :) Reagieren bedeutet für mich, dass etwas getan wird, wird etwas getan, entspricht das einer Handlung .. dazu passen, handeln, entspricht behandeln :) </sarcasm>
 
Hallo,

Also in Java "kann" man auch nicht behandelte Exceptions so abfangen, dass sie nicht bis ganz nach oben durchschlagen. Weiterhin kann man auch die im Beispiel benutzten StackOverFlowExceptions abfangen die von der JVM geworfen werden.
Java:
/**
 * 
 */
package de.tutorials;

import java.util.concurrent.TimeUnit;

/**
 * @author Tom
 */
public class UncaughtExceptionHandlerExample {

  /**
   * @param args
   */
  public static void main(String[] args) {
    new Thread() {
      int counter = 0;


      public void run() {
        while (true) {
          try {
            TimeUnit.SECONDS.sleep(1);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          System.out.println("zzzzzz: " + System.currentTimeMillis());
          if (counter++ > 5) {
            bubu();
          }
        }
      }


      void bubu() {
        bubu();
      }
    }.start();

    new Thread() {
      public void run() {
        while (true) {
          try {
            TimeUnit.SECONDS.sleep(1);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          System.out.println("yyyyyy: " + System.currentTimeMillis());
        }
      }
    }.start();

    Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
      public void uncaughtException(Thread t, Throwable e) {
        System.out.println("Thread: " + t.getName() + " Message: " + e);
      }
    });

  }

}



Gruß Tom
 
Bei .NET war es bis < 2.0 möglich. Seit 2.0 nicht mehr.

Was aber durchaus funktioniert ist das Laden einer Assembly in eine Remote AppDomain (über einen Proxy) und da kannst du nach Auftreten einer fatalen Exception diese neu starten. Die Basisanwendung bleibt davon unbetroffen und versieht weiter ihren Dienst.
 
Zurück