175

什么是展示我完整的正确方法InnerException

我发现我的一些 InnerExceptions 有另一个InnerException,而且非常深入。

将为InnerException.ToString()我完成这项工作还是我需要遍历InnerExceptions并建立一个Stringwith StringBuilder

4

10 回答 10

269

您可以简单地打印exception.ToString()——这还将包括所有嵌套InnerExceptions 的全文。

于 2011-05-08T17:18:32.147 回答
55

我通常这样做是为了消除大部分噪音:

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())
}    
于 2011-05-08T17:32:16.077 回答
48

只需使用exception.ToString()

https://docs.microsoft.com/en-us/dotnet/api/system.exception.tostring#remarks

ToString的默认实现获取抛出当前异常的类名、消息、内部异常调用ToString的结果、调用Environment.StackTrace的结果。如果这些成员中的任何一个为 null,则其值不包含在返回的字符串中。

如果没有错误消息或者是空字符串 (""),则不返回错误消息。内部异常的名称和堆栈跟踪仅在它们不为空时才返回。

exception.ToString() 还将在该异常的内部异常上调用 .ToString() ,依此类推...

于 2011-05-08T17:25:30.577 回答
43

当您想要完整的详细信息(所有消息和堆栈跟踪)和推荐的信息时,@Jon 的答案是最好的解决方案。

但是,可能存在您只需要内部消息的情况,对于这些情况,我使用以下扩展方法:

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

当我有不同的侦听器进行跟踪和日志记录并希望对它们有不同的看法时,我经常使用这种方法。这样我就可以有一个监听器通过电子邮件将带有堆栈跟踪的整个错误发送给开发团队以使用该.ToString()方法进行调试,另一个监听器将每天发生的所有错误的历史记录写入日志文件而没有堆栈跟踪.GetFullMessage()方法。

于 2016-01-29T12:18:51.953 回答
15

要仅打印Message深度异常的 s 部分,您可以执行以下操作:

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

这递归地遍历所有内部异常(包括AggregateExceptions 的情况)以打印其中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));
于 2018-08-27T15:39:22.803 回答
5

我愿意:

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

这个“漂亮打印”所有内部异常,还处理 AggregateExceptions 和 InnerException.Message 与 Message 相同的情况

于 2019-09-30T01:17:02.510 回答
4

如果您使用的是实体框架,exception.ToString()则不会为您提供DbEntityValidationException异常的详细信息。您可能希望使用相同的方法来处理所有异常,例如:

catch (Exception ex)
{
   Log.Error(GetExceptionDetails(ex));
}

其中GetExceptionDetails包含这样的内容:

public static string GetExceptionDetails(Exception ex)
{
    var stringBuilder = new StringBuilder();

    while (ex != null)
    {
        switch (ex)
        {
            case DbEntityValidationException dbEx:
                var errorMessages = dbEx.EntityValidationErrors.SelectMany(x => x.ValidationErrors).Select(x => x.ErrorMessage);
                var fullErrorMessage = string.Join("; ", errorMessages);
                var message = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);

                stringBuilder.Insert(0, dbEx.StackTrace);
                stringBuilder.Insert(0, message);
                break;

            default:
                stringBuilder.Insert(0, ex.StackTrace);
                stringBuilder.Insert(0, ex.Message);
                break;
        }

        ex = ex.InnerException;
    }

    return stringBuilder.ToString();
}
于 2020-08-02T10:14:42.667 回答
3

如果您想要有关所有异常的信息,请使用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
}
于 2018-10-16T08:22:12.620 回答
2

建立在 nawfal 的答案上。

当使用他的答案时,缺少变量 aggrEx,我添加了它。

文件 ExceptionExtensions.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;
        }
    }
}
于 2019-01-15T13:18:48.133 回答
0

我觉得这个更好

public static string GetCompleteMessage(this Exception error)
    {
        System.Text.StringBuilder builder = new StringBuilder();
        Exception realerror = error;
        builder.AppendLine(error.Message);
        while (realerror.InnerException != null)
        {
            builder.AppendLine(realerror.InnerException.Message);
            realerror = realerror.InnerException;
        }
        return builder.ToString();
    }
于 2021-08-13T01:05:06.337 回答