2008-10-01 8 views
35

Ich versuche, eine unbehandelte Ausnahme-Handler in. NET (C#) hinzufügen, die so hilfreich für den "Benutzer" wie möglich sein sollte. Die Endanwender sind meist Programmierer, also brauchen sie nur einen Hinweis darauf, welches Objekt sie falsch manipulieren.In einer .net Exception, wie ein Stacktrace mit Argument Werten

Ich entwickle ein Fenster ähnlich dem Windows XP Fehlerbericht, wenn eine Anwendung abstürzt, aber das gibt so viel sofortige Informationen wie möglich über die Ausnahme geworfen.

Während der Stack-Trace ermöglicht mir (da ich den Quellcode habe), um die Quelle des Problems zu lokalisieren, die Benutzer haben es nicht und so sind sie ohne weitere Informationen verloren. Unnötig zu sagen, dass ich viel Zeit damit verbringen muss, das Tool zu unterstützen.

Es gibt einige Systemausnahmen wie KeyNotFoundException, die von der Dictionary-Sammlung ausgelöst werden, die mich wirklich stören, da sie in der Nachricht den Schlüssel nicht enthalten, der nicht gefunden wurde. Ich kann meinen Code mit tonnenweise Versuchen Catch-Blöcke füllen, aber es ist ziemlich aggressiv und es ist viel mehr Code zu pflegen, nicht zu erwähnen, eine Tonne mehr Strings, die am Ende lokalisiert werden müssen.

Schließlich die Frage: Gibt es eine Möglichkeit, (zur Laufzeit) die Werte der Argumente jeder Funktion in der Call-Stack-Trace zu erhalten? Das allein konnte 90% der Supportanrufe auflösen.

+1

Dies wurde bereits gut beantwortet, aber für zukünftige Referenz möchte ich auch einen Zeiger auf Raymond Chens exzellenten Blogartikel hinzufügen [Wann wird ein Objekt für die Garbage Collection verfügbar?] (Http: //blogs.msdn. com/b/oldnewthing/archive/2010/08/10/10048149.aspx) Unter anderem wird darauf hingewiesen, dass das zuverlässige Sammeln von Argumentwerten aus dem Stack-Trace unmöglich ist, da die Argumente gesammelt werden können, während die referenzierten Methoden noch ausgeführt werden . –

+0

Ich habe diese https://stackoverflow.com/questions/2696691/can-i-get-the-method-local-variables-through-a-stack-trace-in-c gesehen, aber ich weiß nicht wie um das 'StackTrace' vom' Exception' Objekt zu bekommen. Das daran ist eine 'Zeichenfolge'. –

Antwort

0

Mir ist nichts dergleichen bekannt, aber ich wollte es selbst haben. Normalerweise mache ich es selbst, wenn ich Ausnahmen mache, aber wenn es nicht deine ist, die du werfen kannst, dann bist du vielleicht mit uns anderen unterwegs.

1

Ich glaube nicht, dass es einen eingebauten Mechanismus gibt. Wenn Sie jedes Frame des Stack-Trace abrufen, während Sie die Methode im Trace bestimmen können, erhalten Sie nur die Informationen zum reflektierten Typ dieser Methode. Keine Parameterinformationen. Ich denke, das ist der Grund, warum einige Ausnahmen, insbesondere ArgumentException, et. al. Stellen Sie einen Mechanismus zur Verfügung, um den Wert des Arguments anzugeben, das an der Exception beteiligt ist, da es keinen einfachen Weg gibt, es zu bekommen.

7

Ich glaube nicht, dass System.Diagnostics.StackFrame Argument Informationen (andere als die Methode Signatur) liefert.

Sie können die lästigen Anrufe mit Trace-Protokollierung über AOP instrumentieren oder sogar die Ausnahmenabfangfunktionen verwenden, um eine bedingte Protokollierung durchzuführen, ohne Ihren Code zu verwerfen. Schauen Sie sich um http://www.postsharp.org/.

0

Ich weiß nicht, eine Möglichkeit, die Werte der Argumente für jede Funktion in dem Aufruf-Stack-Trace zu erhalten, aber in eine eine Lösung wäre, die spezifische Ausnahme zu fangen (KeyNotFoundException in Ihrem Beispiel) und wieder werfen sie neue Ausnahme Das erlaubt Ihnen, zusätzliche Informationen verknüpfen Sie wünschen

Zum Beispiel:

Dim sKey as String = "some-key" 
Dim sValue as String = String.Empty 

Try 
    sValue = Dictionary(sKey) 
Catch KeyEx As KeyNotFoundException 
    Throw New KeyNotFoundException("Class.Function() - Couldn't find [" & sKey & "]", KeyEx) 
End Try 

Ich schätze Ihre Aussage über die Fehlerzeichenfolgen zu lokalisieren, aber wenn Ihr Publikum sind "meist Programmierer dann Konvention bereits diktiert ein Verständnis der englischen Sprache zu einem gewissen Grad (richtig oder falsch - aber das ist eine andere Debatte!)

+1

Ja, ich weiß, ich kann, aber das ist genau das, was ich versuche zu vermeiden. Zuletzt habe ich über 200 Anrufe zu Hashtables gemacht und sie werden jeden Tag neu eingeführt. Ich denke an eine Hilfsfunktion, aber es sieht immer noch hässlich aus und löst nur die KeyNotFoundException. – Caerbanog

+1

Vielleicht eine Hilfsfunktion ist der Weg zu gehen, sorry, ich konnte nicht helfen (zu meinen Favoriten hinzugefügt, so dass ich überprüfen kann, um zu sehen, was Sie entscheiden): o) – Andrew

1

Da die Endbenutzer Entwickler sind, können Sie ihnen eine Version zur Verfügung stellen, die die Protokollierung aller übergebenen Schlüsselwerte/Argumente ermöglicht. Und stellen Sie eine Einrichtung zur Verfügung, mit der sie die Protokollierung ein- und ausschalten können.

0

Sobald Sie die Ausnahme haben, sind die beiden Dinge, die Sie interessieren, System.Diagnostics.StackTrace und System.Diagnostics.StackFrame-

Es ist ein MSDN Beispiel here

+0

Ok, aber wenn ich die 'Ausnahme' habe ich don Ich sehe keinen Weg, um das 'StackTrace'-Objekt zu erhalten. Die 'StackTrace' in der Ausnahme ist eine bereits serialisierte String-Repräsentation des Aufruf-Stacks. –

+0

@CsabaToth https://msdn.microsoft.com/en-us/library/4ce0ktkk(v=vs.110).aspx – slf

+0

Sie meinen, dass ich "StackTrace" -Objekt mit der Ausnahme als Konstruktor Parameter erstellen? Ich denke, ich werde versuchen, dass –

3

Leider kann man nicht die tatsächlichen Werte von Parametern aus der Aufrufliste erhalten, außer mit Debugging-Tool tatsächlich den Antrag beigefügt. Wenn Sie jedoch die StackTrace- und StackFrame-Objekte in System.Diagnostics verwenden, können Sie den Aufruf-Stack durchlaufen und alle aufgerufenen Methoden sowie die Parameternamen und -typen auslesen. Sie würden diese wie tun:

System.Diagnostics.StackTrace callStack = new System.Diagnostics.StackTrace(); 
System.Diagnostics.StackFrame frame = null; 
System.Reflection.MethodBase calledMethod = null; 
System.Reflection.ParameterInfo [] passedParams = null; 
for (int x = 0; x < callStack.FrameCount; x++) 
{ 
    frame = callStack.GetFrame(x); 
    calledMethod = frame.GetMethod(); 
    passedParams = calledMethod.GetParameters(); 
    foreach (System.Reflection.ParameterInfo param in passedParams) 
     System.Console.WriteLine(param.ToString()); 
} 

Wenn Sie Ist-Werte müssen dann Minidumps müssen Sie gehen zu nehmen und zu analysieren, sie fürchte ich.

http://www.debuginfo.com/tools/clrdump.html

+4

Das Problem damit ist, dass Sie den Stapel aus dem Catch, nicht den Stapel zum Zeitpunkt der Ausnahme bekommen. – GeekyMonkey

1

es theoretisch möglich ist zu tun, was Sie wollen durch die Nutzung der Portable Executable (PE) Dateiformat nehmen die Variablentypen und Offsets zu bekommen, aber ich: Informationen auf Dump-Informationen zu erhalten finden Sie unter vor ein paar Jahren in eine [Dokumentations-] Wand gerannt, um dies zu tun. Viel Glück!

1

Wenn Sie tun könnten, was Sie suchen, würden Sie einen integralen Teil der .NET-Sicherheit besiegen.

Die beste Option in diesem Fall, es an einen Debugger oder Profiler (jeder von ihnen kann auf diese Werte zugreifen) anzuhängen. Ersteres kann angehängt werden, letzteres muss vor dem Programmstart aktiv sein.

+1

+1 für die Erwähnung eines interessanten Problems (Sicherheit); Aber könnten Sie ein wenig mehr darüber sprechen, wie dies die Sicherheit brechen würde, oder besser, warum betrachten Sie diesen Aspekt als "integral"? – stakx

5

Ebenso habe ich nichts gefunden, um die Parameter zur Laufzeit automatisch abzuleiten. Stattdessen habe ich ein Visual Studio-Add-In generieren Code verwendet, die explizit die Parameter Pakete auf, wie folgt aus:

public class ExceptionHandler 
{ 
    public static bool HandleException(Exception ex, IList<Param> parameters) 
    { 
     /* 
     * Log the exception 
     * 
     * Return true to rethrow the original exception, 
     * else false 
     */ 
    } 
} 

public class Param 
{ 
    public string Name { get; set; } 
    public object Value { get; set; } 
} 

public class MyClass 
{ 
    public void RenderSomeText(int lineNumber, string text, RenderingContext context) 
    { 
     try 
     { 
      /* 
      * Do some work 
      */ 
      throw new ApplicationException("Something bad happened"); 
     } 
     catch (Exception ex) 
     { 
      if (ExceptionHandler.HandleException(
        ex, 
        new List<Param> 
        { 
         new Param { Name = "lineNumber", Value=lineNumber }, 
         new Param { Name = "text", Value=text }, 
         new Param { Name = "context", Value=context} 
        })) 
      { 
       throw; 
      } 
     } 
    } 
} 

EDIT: oder alternativ durch den Parameter Herstellung eines params Array Handle:

public static bool HandleException(Exception ex, params Param[] parameters) 
{ 
    ... 
} 

... 
if (ExceptionHandler.HandleException(
        ex, 
        new Param { Name = "lineNumber", Value=lineNumber }, 
        new Param { Name = "text", Value=text }, 
        new Param { Name = "context", Value=context} 
        )) 
{ 
    throw; 
} 
... 

Es ist ein bisschen mühsam, den zusätzlichen Code zu generieren, um die Parameter explizit an den Ausnahmebehandler zu übergeben, aber mit der Verwendung eines Add-Ins können Sie es zumindest automatisieren.

kann ein benutzerdefiniertes Attribut verwendet werden, um alle Parameter mit Anmerkungen versehen, die Sie die Exception-Handler die Add-In nicht passieren wollen:

public UserToken RegisterUser(string userId, [NoLog] string password) 
{ 
} 

2. EDIT:

Wohlgemerkt, ich vollständig über AVIcode vergessen d:

http://www.avicode.com/

Sie Anrufunterbrechungstechniken benutzen, um genau diese Art von Informationen zur Verfügung zu stellen, also muss es möglich sein.

2

Es gibt ein Software-Tool von redgate da draußen, das sehr vielversprechend aussieht.

http://www.red-gate.com/products/dotnet-development/smartassembly/

Zurzeit sind unsere Kunden Fehlermeldungen per eMail wir sammeln und ich manchmal mit einigen wichtigen Daten fehlen (meist einige sehr grundlegende Variablen, wie die ID aus dem aktuellen Datensatz so dass ich den Fehler reproduzieren kann) kämpfen. Ich habe dieses Tool noch nicht getestet, aber von meinem Verständnis her macht es das, was die Argumentwerte und lokalen Variablen vom Stapel sammelt.

Verwandte Themen