web-dev-qa-db-fra.com

Quelle est la manière appropriée d’afficher l’InnerException complète?

Quelle est la bonne façon de montrer ma InnerException complète?.

J'ai trouvé que certaines de mes InnerExceptions ont une autre InnerException et cela va assez profond.

InnerException.ToString() fera-t-il le travail à ma place ou dois-je parcourir la InnerExceptions et créer une String avec StringBuilder?

123
Willem

Vous pouvez simplement imprimer exception.ToString() - qui inclura également le texte intégral pour tous les InnerExceptions imbriqués.

195
Jon

Il suffit d'utiliser exception.ToString()

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

L'implémentation par défaut de ToString obtient le nom de la classe qui a levé l'exception actuelle, le message, le résultat de l'appel de ToString sur l'exception interne et le résultat de l'appel de Environment.StackTrace. Si l'un de ces membres est null, sa valeur n'est pas incluse dans la chaîne renvoyée.

S'il n'y a pas de message d'erreur ou s'il s'agit d'une chaîne vide (""), aucun message d'erreur n'est renvoyé. Le nom de l'exception interne et la trace de la pile ne sont renvoyés que s'ils ne sont pas nuls.

exception.ToString () appellera également .ToString () sur l'exception interne de cette exception, et ainsi de suite ...

40
Rob P.

J'ai l'habitude de faire comme ça pour enlever la plupart du bruit:

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

    Console.WriteLine(realerror.ToString())
}    

Edit: / J'ai oublié cette réponse et je suis surpris que personne ne dise que vous pouvez simplement faire

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

La réponse de @ Jon est la meilleure solution lorsque vous souhaitez des détails complets (tous les messages et la trace de la pile) et celle recommandée. 

Cependant, il peut arriver que vous souhaitiez uniquement les messages internes, et j'utilise la méthode d'extension suivante:

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

J'utilise souvent cette méthode lorsque différents écouteurs effectuent le traçage et la journalisation et que je souhaite avoir différentes vues sur eux. De cette façon, je peux avoir un auditeur qui envoie toute l’erreur avec trace de pile par courrier électronique à l’équipe de développement pour le débogage à l’aide de la méthode .ToString() et un qui écrit un fichier de connexion avec l’historique de toutes les erreurs survenues chaque jour sans trace de pile. avec la méthode .GetFullMessage().

28
ThomazMoura

Pour imprimer simplement la partie Messages des exceptions profondes, vous pouvez faire quelque chose comme ceci:

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;
        }
    }
}

Cela passe de manière récursive dans toutes les exceptions internes (y compris le cas de AggregateExceptions) pour imprimer toutes les propriétés Message qui y sont contenues, délimitées par un saut de ligne.

Par exemple. 

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());

Aggr ex externe s'est produit.
Aggr intérieure ex.
Le numéro n'est pas au format correct.
Accès au fichier non autorisé.
Pas administrateur.


Vous devrez écouter les autres propriétés Exception / propriétés pour plus de détails. Par exemple Data aura des informations. Vous pourriez faire:

foreach (DictionaryEntry kvp in exception.Data)

Pour obtenir toutes les propriétés dérivées (pas sur la classe Exception de base), vous pouvez faire:

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

Si vous souhaitez des informations sur toutes les exceptions, utilisez exception.ToString(). Il collectera des données de toutes les exceptions internes.

Si vous ne voulez que l'exception d'origine, utilisez exception.GetBaseException().ToString(). Cela vous donnera la première exception, par exemple. l'exception interne la plus profonde ou l'exception actuelle s'il n'y a pas d'exception interne.

Exemple:

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
}
0
dkostas

accumulation sur la réponse de nawfal.

en utilisant sa réponse, il manquait une variable aggrEx, je l'ai ajoutée.

fichier 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(e => e.Message.Trim() + "\r\n" + e.StackTrace.Trim() );
            string flattened = String.Join("\r\n\r\n", messages); // <-- the separator here
            return flattened;
        }
    }
}
0
Shimon Doodkin