Wie kann die vollständige InnerException richtig angezeigt werden?


155

Was ist der richtige Weg, um meine volle zu zeigen InnerException.

Ich habe festgestellt, dass einige meiner InnerExceptions eine andere haben InnerExceptionund das geht ziemlich tief.

Erledige InnerException.ToString()ich den Job für mich oder muss ich das durchlaufen InnerExceptionsund ein Stringmit aufbauen StringBuilder?


Warum müssen Sie die innere Ausnahme zeigen?
Akram Shahda

26
@Akram, weil es meistens die innere Ausnahme ist, die interessant ist. Ein Beispiel ist der XmlSerializer, der nur dann eine InvalidOperationException auslöst, wenn etwas schief geht. Was schief gelaufen ist, ist in der inneren Ausnahme.
Adrianm

4
@AkramShahda Nun, vielleicht möchten Sie diese Methode in Ihrer Protokollierung verwenden?
Cederlof

In Verbindung stehender Beitrag - Exception.Message vs Exception.ToString ()
RBT

Antworten:


239

Sie können einfach drucken exception.ToString()- dazu gehört auch der vollständige Text für alle verschachtelten InnerExceptions.


18
Dies beinhaltet auch eine
Menge

Nur aus Gründen der Prägnanz benötigen Sie .ToString () nicht. Nur die Verwendung einer Ausnahme bewirkt dasselbe.
Alex Stephens

3
@AlexStephens Sie haben Recht, aber nur, wenn Sie ein implizites Casting "to string" aus irgendeinem Grund haben, wie vorhergehende Zeichenfolge: "bla" + Ausnahme
oo_dev

1
Zu Ihrer Information : Es werden keine benutzerdefinierten ToStringMethoden für innere Ausnahmen aufgerufen, wie unter Warum ruft System.Exception.ToString keinen virtuellen ToString für innere Ausnahmen auf? .
Jeff B

45

Benutz einfach exception.ToString()

http://msdn.microsoft.com/en-us/library/system.exception.tostring.aspx

Die Standardimplementierung von ToString erhält den Namen der Klasse, die die aktuelle Ausnahme ausgelöst hat, die Nachricht, das Ergebnis des Aufrufs von ToString für die innere Ausnahme und das Ergebnis des Aufrufs von Environment.StackTrace. Wenn eines dieser Elemente null ist, ist sein Wert nicht in der zurückgegebenen Zeichenfolge enthalten.

Wenn keine Fehlermeldung vorliegt oder wenn es sich um eine leere Zeichenfolge ("") handelt, wird keine Fehlermeldung zurückgegeben. Der Name der inneren Ausnahme und die Stapelverfolgung werden nur zurückgegeben, wenn sie nicht null sind.

exception.ToString () ruft auch .ToString () für die innere Ausnahme dieser Ausnahme auf und so weiter ...


45

Normalerweise mag ich das, um den größten Teil des Rauschens zu entfernen:

void LogException(Exception error) {
    Exception realerror = error;
    while (realerror.InnerException != null)
        realerror = realerror.InnerException;

    Console.WriteLine(realerror.ToString())
}    

Bearbeiten: Ich habe diese Antwort vergessen und bin überrascht, dass niemand darauf hingewiesen hat, dass Sie einfach tun können

void LogException(Exception error) {
    Console.WriteLine(error.GetBaseException().ToString())
}    

Diese Methode verbirgt alles außer der tiefsten inneren Ausnahme. Wenn das etwas Alltägliches wie ein "Teilen durch Null" -Fehler wäre, wäre unklar, wo es aufgetreten ist und was dazu geführt hat. Offensichtlich ist eine vollständige Stapelverfolgung normalerweise ein chaotischer Overkill, aber nur das Lesen der inneren Ausnahme ist das andere Extrem. Die Antwort von user3016982 ist weitaus besser. Sie erhalten jede Ausnahmemeldung im Stapel ohne die böse Spur.
JamesHoux

1
@ JamesHoux Welches ist die Antwort "user3016982"? Ich kann ihn hier nicht finden.
Maracuja-Saft

Der Benutzer3016982 ist ThomazMoura, siehe: stackoverflow.com/users/3016982/thomazmoura
Apfelkuacha

@JamesHoux, die innere Ausnahme hat eine vollständige Stapelverfolgung, die zeigt, wo der Fehler aufgetreten ist und was dazu geführt hat. Verstehen Sie nicht, welche zusätzlichen Informationen Sie von den entfernten Stapelspuren erhalten. Ausnahmemeldungen sind eine andere Sache und es kann nützlich sein, alle zu sammeln.
Adrianm

2
Warum benutzt du nicht einfach error.GetBaseException(). Ich glaube, das macht das gleiche ...
Robba

37

Die Antwort von @ Jon ist die beste Lösung, wenn Sie alle Details (alle Nachrichten und die Stapelverfolgung) und die empfohlene Lösung wünschen.

Es kann jedoch Fälle geben, in denen Sie nur die inneren Nachrichten möchten, und für diese Fälle verwende ich die folgende Erweiterungsmethode:

public static class ExceptionExtensions
{
    public static string GetFullMessage(this Exception ex)
    {
        return ex.InnerException == null 
             ? ex.Message 
             : ex.Message + " --> " + ex.InnerException.GetFullMessage();
    }
}

Ich verwende diese Methode oft, wenn ich unterschiedliche Listener zum Verfolgen und Protokollieren habe und unterschiedliche Ansichten zu ihnen haben möchte. Auf diese Weise kann ich einen Listener haben, der den gesamten Fehler mit Stack-Trace per E-Mail an das Entwicklerteam zum Debuggen mit der .ToString()Methode sendet , und einen, der eine Anmeldedatei mit dem Verlauf aller Fehler schreibt, die jeden Tag ohne den Stack-Trace mit aufgetreten sind die .GetFullMessage()Methode.


7
Zu exAggregateException
Ihrer Information

3
Dies sollte eine Standard-.NET-Methode sein. Jeder sollte dies verwenden.
JamesHoux

9

Um nur den MessageTeil der tiefen Ausnahmen hübsch auszudrucken , können Sie Folgendes tun:

public static string ToFormattedString(this Exception exception)
{
    IEnumerable<string> messages = exception
        .GetAllExceptions()
        .Where(e => !String.IsNullOrWhiteSpace(e.Message))
        .Select(e => e.Message.Trim());
    string flattened = String.Join(Environment.NewLine, messages); // <-- the separator here
    return flattened;
}

public static IEnumerable<Exception> GetAllExceptions(this Exception exception)
{
    yield return exception;

    if (exception is AggregateException aggrEx)
    {
        foreach (Exception innerEx in aggrEx.InnerExceptions.SelectMany(e => e.GetAllExceptions()))
        {
            yield return innerEx;
        }
    }
    else if (exception.InnerException != null)
    {
        foreach (Exception innerEx in exception.InnerException.GetAllExceptions())
        {
            yield return innerEx;
        }
    }
}

Dies durchläuft rekursiv alle inneren Ausnahmen (einschließlich des Falls von AggregateExceptions), um alle darin Messageenthaltenen Eigenschaften zu drucken , die durch Zeilenumbrüche begrenzt sind.

Z.B

var outerAggrEx = new AggregateException(
    "Outer aggr ex occurred.",
    new AggregateException("Inner aggr ex.", new FormatException("Number isn't in correct format.")),
    new IOException("Unauthorized file access.", new SecurityException("Not administrator.")));
Console.WriteLine(outerAggrEx.ToFormattedString());

Äußerer Aggr ex trat auf.
Innerer Aggr.
Die Nummer hat nicht das richtige Format.
Nicht autorisierter Dateizugriff.
Kein Administrator.


Sie müssen andere Ausnahmeeigenschaften anhören, um weitere Details zu erhalten. Zum Beispiel Datawird einige Informationen haben. Du könntest es tun:

foreach (DictionaryEntry kvp in exception.Data)

Um alle abgeleiteten Eigenschaften (nicht für die Basisklasse Exception) abzurufen, können Sie Folgendes tun:

exception
    .GetType()
    .GetProperties()
    .Where(p => p.CanRead)
    .Where(p => p.GetMethod.GetBaseDefinition().DeclaringType != typeof(Exception));

+1, das ist fast genau das gleiche wie ich. Suchen Sie nach einer Eigenschaft, die IEnumerable<Exception>anstelle einer harten Codierung implementiert wird AggregrateException, um andere ähnliche Typen zu verarbeiten. Auch Probleme ausschließen p.IsSpecialNameund pi.GetIndexParameters().Length != 0vermeiden. Es ist auch eine gute Idee, den Namen des Ausnahmetyps in die Ausgabe aufzunehmen
adrianm

@adrianm guter Punkt über Immobilieninfo-Checks. Bei der Überprüfung auf Sammlung von Ausnahmen geht es darum, wo Sie die Grenze ziehen möchten. Sicher kann das auch gemacht werden ..
Nawfal

4

Ich mache:

namespace System {
  public static class ExtensionMethods {
    public static string FullMessage(this Exception ex) {
      if (ex is AggregateException aex) return aex.InnerExceptions.Aggregate("[ ", (total, next) => $"{total}[{next.FullMessage()}] ") + "]";
      var msg = ex.Message.Replace(", see inner exception.", "").Trim();
      var innerMsg = ex.InnerException?.FullMessage();
      if (innerMsg is object && innerMsg!=msg) msg = $"{msg} [ {innerMsg} ]";
      return msg;
    }
  }
}

Dies "druckt" alle inneren Ausnahmen und behandelt auch AggregateExceptions und Fälle, in denen InnerException.Message mit Message identisch ist


3

Wenn Sie Informationen zu allen Ausnahmen wünschen, verwenden Sie exception.ToString(). Es werden Daten aus allen inneren Ausnahmen gesammelt.

Wenn Sie nur die ursprüngliche Ausnahme möchten, verwenden Sie exception.GetBaseException().ToString(). Dadurch erhalten Sie die erste Ausnahme, z. B. die tiefste innere Ausnahme oder die aktuelle Ausnahme, wenn keine innere Ausnahme vorliegt.

Beispiel:

try {
    Exception ex1 = new Exception( "Original" );
    Exception ex2 = new Exception( "Second", ex1 );
    Exception ex3 = new Exception( "Third", ex2 );
    throw ex3;
} catch( Exception ex ) {
    // ex => ex3
    Exception baseEx = ex.GetBaseException(); // => ex1
}

2

Aufbau auf Nawfals Antwort.

Als ich seine Antwort verwendete, fehlte eine Variable aggrEx. Ich fügte sie hinzu.

Datei ExceptionExtenstions.class:

// example usage:
// try{ ... } catch(Exception e) { MessageBox.Show(e.ToFormattedString()); }

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace YourNamespace
{
    public static class ExceptionExtensions
    {

        public static IEnumerable<Exception> GetAllExceptions(this Exception exception)
        {
            yield return exception;

            if (exception is AggregateException )
            {
                var aggrEx = exception as AggregateException;
                foreach (Exception innerEx in aggrEx.InnerExceptions.SelectMany(e => e.GetAllExceptions()))
                {
                    yield return innerEx;
                }
            }
            else if (exception.InnerException != null)
            {
                foreach (Exception innerEx in exception.InnerException.GetAllExceptions())
                {
                    yield return innerEx;
                }
            }
        }


        public static string ToFormattedString(this Exception exception)
        {
            IEnumerable<string> messages = exception
                .GetAllExceptions()
                .Where(e => !String.IsNullOrWhiteSpace(e.Message))
                .Select(exceptionPart => exceptionPart.Message.Trim() + "\r\n" + (exceptionPart.StackTrace!=null? exceptionPart.StackTrace.Trim():"") );
            string flattened = String.Join("\r\n\r\n", messages); // <-- the separator here
            return flattened;
        }
    }
}

Ich hatte eine Ausnahme, weil:e.StackTrace == null
Andrei Krasutski

1
Ich habe .Select (e => e.Message.Trim () + "\ r \ n" + (e.StackTrace! = Null? StackTrace.Trim (): "") aktualisiert. Vielleicht hilft das
Shimon Doodkin
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.