Каков правильный способ отображения полного InnerException?

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

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

Будет ли InnerException.ToString() выполнять задание для меня или мне нужно пройти через InnerExceptions и создать a String с помощью StringBuilder?

Ответ 1

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

Ответ 2

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

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

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

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

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

Ответ 3

Я обычно делаю так, чтобы удалить большую часть шума:

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

Ответ 4

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

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

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

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

Ответ 5

Чтобы печатать только часть 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), чтобы распечатать все содержащиеся в них свойства 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());

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


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

foreach (DictionaryEntry kvp in exception.Data)

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

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

Ответ 6

Если вы хотите получить информацию обо всех исключениях, тогда используйте 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
}

Ответ 7

Накапливаться на Nawfal ответ.

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

файл 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;
        }
    }
}

Ответ 8

Я делаю:

namespace System {
  public static class ExtensionMethods {
    public static string FullMessage(this Exception ex) {
      var msg = ex.Message.Replace(", see inner exception.", "").Trim();
      if (ex.InnerException != null) msg += " [" + ex.InnerException.FullMessage() + "]";
      return msg;
    }
  }
}

Ответ 9

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

catch (Exception ex)
{
  string[] myex = ex.InnerException.Message.Split('"');
  MessageBox.Show(myex[15]);
}

поскольку я использовал myex [15], потому что в основном myex [15] имеет сообщение на правильном английском языке, которое легко понять.