显示完整 InnerException 的正确方法是什么?

问题描述 投票:0回答:12

展示我完整

InnerException
的正确方式是什么。

我发现我的一些 InnerExceptions 还有另一个

InnerException
,而且这种情况非常严重。

InnerException.ToString()
会为我做这项工作吗?还是我需要循环遍历
InnerExceptions
并用
String
建立一个
StringBuilder

c# exception inner-exception
12个回答
300
投票

您可以简单地打印

exception.ToString()
——这还将包括所有嵌套
InnerException
的全文。


68
投票

我通常这样做来消除大部分噪音:

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

56
投票

只需使用

exception.ToString()

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

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

如果没有错误信息或者为空字符串(“”),则不返回错误信息。仅当内部异常的名称和堆栈跟踪不为 null 时才会返回。

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


48
投票
当您想要完整的详细信息(所有消息和堆栈跟踪)和推荐的解决方案时,@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()
 方法进行堆栈跟踪。


17
投票
要漂亮地打印深层异常的

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

发生外部聚合。

内部聚合前。
号码格式不正确。
未经授权的文件访问。
不是管理员。


您将需要监听其他

Exception 属性以获取更多详细信息。例如Data

会有一些信息。你可以这样做:

foreach (DictionaryEntry kvp in exception.Data)

要获取所有派生属性(不在基

Exception

类上),你可以这样做:

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

6
投票
我愿意:

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

这个“漂亮地打印”所有内部异常,并且还处理 AggregateException 以及 InnerException.Message 与 Message 相同的情况


6
投票
如果您使用实体框架,

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

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 }
    

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

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

0
投票
此代码生成异常的格式化

HTML

 表示:

const string _HTML_TAB = "&nbsp;&nbsp;&nbsp;"; public static string ToHtmlString(this Exception ex, int level = 0) { string message = GetText("Message", ex.Message, level); if (ex.InnerException != null && level < 30) { message += ToHtmlString(ex.InnerException, level + 1); } else { message += GetText("StackTrace", ex.StackTrace, level); ; message += GetText("Source", ex.Source, level); ; message += GetText("TargetSite", ex.TargetSite.ToString(), level); } return message; } private static string GetText(string headline, string text, int level) { var indentText = string.Join(_HTML_TAB, new string[level + 1]); var newLine = $"<br />{indentText}{_HTML_TAB}"; return $"{indentText}<b>{headline}</b>{newLine}" + $"{text.Replace(Environment.NewLine, newLine)}<br /><br />"; }
    

0
投票
如果出现聚合错误,我在

catch

 子句中使用此代码:

catch (AggregateException ae) { foreach (var e in ae.InnerExceptions) { if (e is TaskCanceledException taskException) Console.WriteLine("Unable to compute mean: {taskException.Message}"); if (e is OperationCanceledException operationException) Console.WriteLine($"Unable to compute mean: {operationException.Message}"); else Console.WriteLine("Exception: " + e.GetType().Name); } }
    
© www.soinside.com 2019 - 2024. All rights reserved.