Как правильно отобразить полное InnerException? - PullRequest
134 голосов
/ 08 мая 2011

Как правильно показать мои полные InnerException.

Я обнаружил, что у некоторых из моих InnerException есть еще InnerException, и это происходит довольно глубоко.* сделай работу за меня или мне нужно перебрать InnerExceptions и создать String с StringBuilder?

Ответы [ 7 ]

208 голосов
/ 08 мая 2011

Вы можете просто напечатать exception.ToString() - это также будет включать полный текст для всех вложенных InnerException s.

41 голосов
/ 08 мая 2011

Просто используйте exception.ToString()

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

Реализация по умолчанию ToString получает имя класса, выдавшего текущее исключение, сообщение, результат вызоваToString для внутреннего исключения и результат вызова Environment.StackTrace.Если какой-либо из этих членов имеет значение null, его значение не включается в возвращаемую строку.

Если сообщения об ошибке нет или это пустая строка (""), сообщение об ошибке не возвращается.Имя внутреннего исключения и трассировка стека возвращаются только в том случае, если они не равны нулю.

exception.ToString () также вызовет .ToString () для внутреннего исключения этого исключения и так далее...

36 голосов
/ 08 мая 2011

Обычно я делаю это, чтобы удалить большую часть шума:

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

    Console.WriteLine(realerror.ToString())
}    

Редактировать: Я забыл об этом ответе и удивился, что никто не указал, что вы можете просто сделать

void LogException(Exception error) {
    Console.WriteLine(error.GetBaseException().ToString())
}    
30 голосов
/ 29 января 2016

@ Ответ Джона - лучшее решение, когда вам нужна полная детализация (все сообщения и трассировка стека) и рекомендуемое.

Однако могут быть случаи, когда вам просто нужны внутренние сообщения, и для этих случаев я использую следующий метод расширения:

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

Я часто использую этот метод, когда у меня разные слушатели для трассировки и ведения журнала, и я хочу иметь разные взгляды на них. Таким образом, у меня может быть один прослушиватель, который отправляет всю ошибку с трассировкой стека по электронной почте команде разработчиков для отладки с использованием метода .ToString(), и тот, который записывает файл журнала с историей всех ошибок, которые произошли каждый день без трассировка стека методом .GetFullMessage().

5 голосов
/ 27 августа 2018

Чтобы распечатать только часть глубоких исключений Message, вы можете сделать что-то вроде этого:

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

Это рекурсивно проходит через все внутренние исключения (включая случай AggregateException s), чтобы напечатать все содержащиеся в них свойства Message, ограниченные переводом строки.

например.

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

Произошло внешнее соединение.
Внутренний агр от
Номер не в правильном формате.
Несанкционированный доступ к файлу.
Не администратор.


Вам нужно будет прослушать другие Exception свойства для получения более подробной информации. Например, Data будет иметь некоторую информацию. Вы могли бы сделать:

foreach (DictionaryEntry kvp in exception.Data)

Чтобы получить все производные свойства (не для базового Exception класса), вы можете сделать:

exception
    .GetType()
    .GetProperties()
    .Where(p => p.CanRead)
    .Where(p => p.GetMethod.GetBaseDefinition().DeclaringType != typeof(Exception));
1 голос
/ 15 января 2019

наращивание ответа nawfal.

при использовании его ответа отсутствовала переменная aggrEx, я добавил ее.

file 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;
        }
    }
}
0 голосов
/ 16 октября 2018

Если вы хотите получить информацию обо всех исключениях, используйте exception.ToString(). Он будет собирать данные из всех внутренних исключений.

Если вы хотите только оригинальное исключение, используйте exception.GetBaseException().ToString(). Это даст вам первое исключение, например, самое глубокое внутреннее исключение или текущее исключение, если нет внутреннего исключения.

Пример:

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