public void appending_multi_lines_to_empty_lines() { { StringBuilder b = new StringBuilder(); string text = Environment.NewLine; string t = b.AppendMultiLine("|", text, true).ToString(); t.Should().Be("|"); } { StringBuilder b = new StringBuilder(); string text = Environment.NewLine + Environment.NewLine; string t = b.AppendMultiLine("|", text, true).ToString(); t.Should().Be("|" + Environment.NewLine + "|"); } { StringBuilder b = new StringBuilder(); string text = Environment.NewLine + Environment.NewLine + Environment.NewLine; string t = b.AppendMultiLine("|", text, true).ToString(); t.Should().Be("|" + Environment.NewLine + "|" + Environment.NewLine + "|"); } { StringBuilder b = new StringBuilder(); string text = Environment.NewLine + Environment.NewLine + Environment.NewLine + "a"; string t = b.AppendMultiLine("|", text, true).ToString(); t.Should().Be("|" + Environment.NewLine + "|" + Environment.NewLine + "|" + Environment.NewLine + "|a"); } }
public void appending_multi_lines_with_prefixLastEmptyLine() { string text = @"First line. Second line. "; { StringBuilder b = new StringBuilder(); string t = b.AppendMultiLine("|", text, true, prefixLastEmptyLine: false).ToString(); t.Should().Be(@"|First line. |Second line. | |".NormalizeEOL()); } { StringBuilder b = new StringBuilder(); string t = b.AppendMultiLine("|", text, true, prefixLastEmptyLine: true).ToString(); t.Should().Be(@"|First line. |Second line. | | |".NormalizeEOL()); } }
public void appending_multi_lines_to_empty_lines() { { StringBuilder b = new StringBuilder(); string text = Environment.NewLine; string t = b.AppendMultiLine("|", text, true).ToString(); Assert.That(t, Is.EqualTo("|")); } { StringBuilder b = new StringBuilder(); string text = Environment.NewLine + Environment.NewLine; string t = b.AppendMultiLine("|", text, true).ToString(); Assert.That(t, Is.EqualTo("|" + Environment.NewLine + "|")); } { StringBuilder b = new StringBuilder(); string text = Environment.NewLine + Environment.NewLine + Environment.NewLine; string t = b.AppendMultiLine("|", text, true).ToString(); Assert.That(t, Is.EqualTo("|" + Environment.NewLine + "|" + Environment.NewLine + "|")); } { StringBuilder b = new StringBuilder(); string text = Environment.NewLine + Environment.NewLine + Environment.NewLine + "a"; string t = b.AppendMultiLine("|", text, true).ToString(); Assert.That(t, Is.EqualTo("|" + Environment.NewLine + "|" + Environment.NewLine + "|" + Environment.NewLine + "|a")); } }
static StringBuilder AppendField(StringBuilder b, string prefix, string label, string text) { b.Append(prefix).Append(label).Append(": ").Append(' ', 10 - label.Length); prefix += new string( ' ', 12 ); b.AppendMultiLine(prefix, text, false).AppendLine(); return(b); }
long PrefixWithOurExtension(Stopwatch w, string f, string[] results) { GC.Collect(); w.Restart(); StringBuilder b = new StringBuilder(); for (int i = 0; i < results.Length; ++i) { // We must use the prefixLastEmptyLine to match the way the naive implementation works. results[i] = b.AppendMultiLine(prefix, f, false, prefixLastEmptyLine: true).ToString(); b.Clear(); } w.Stop(); return(w.ElapsedTicks); }
public void appending_multi_lines_with_a_prefix_with_null_or_empty_or_one_line() { { StringBuilder b = new StringBuilder(); string text = @"One line."; string t = b.AppendMultiLine( "|", text, true ).ToString(); Assert.That( t, Is.EqualTo( @"|One line." ) ); } { StringBuilder b = new StringBuilder(); string text = @""; string t = b.AppendMultiLine( "|", text, true ).ToString(); Assert.That( t, Is.EqualTo( @"|" ) ); } { StringBuilder b = new StringBuilder(); string text = null; string t = b.AppendMultiLine( "|", text, true ).ToString(); Assert.That( t, Is.EqualTo( @"|" ) ); } { StringBuilder b = new StringBuilder(); string text = @"One line."; string t = b.AppendMultiLine( "|", text, false ).ToString(); Assert.That( t, Is.EqualTo( @"One line." ) ); } { StringBuilder b = new StringBuilder(); string text = @""; string t = b.AppendMultiLine( "|", text, false ).ToString(); Assert.That( t, Is.EqualTo( @"" ) ); } { StringBuilder b = new StringBuilder(); string text = null; string t = b.AppendMultiLine( "|", text, false ).ToString(); Assert.That( t, Is.EqualTo( @"" ) ); } }
public void appending_multi_lines_with_a_prefix_with_null_or_empty_or_one_line() { { StringBuilder b = new StringBuilder(); string text = @"One line."; string t = b.AppendMultiLine("|", text, true).ToString(); Assert.That(t, Is.EqualTo(@"|One line.")); } { StringBuilder b = new StringBuilder(); string text = @""; string t = b.AppendMultiLine("|", text, true).ToString(); Assert.That(t, Is.EqualTo(@"|")); } { StringBuilder b = new StringBuilder(); string text = null; string t = b.AppendMultiLine("|", text, true).ToString(); Assert.That(t, Is.EqualTo(@"|")); } { StringBuilder b = new StringBuilder(); string text = @"One line."; string t = b.AppendMultiLine("|", text, false).ToString(); Assert.That(t, Is.EqualTo(@"One line.")); } { StringBuilder b = new StringBuilder(); string text = @""; string t = b.AppendMultiLine("|", text, false).ToString(); Assert.That(t, Is.EqualTo(@"")); } { StringBuilder b = new StringBuilder(); string text = null; string t = b.AppendMultiLine("|", text, false).ToString(); Assert.That(t, Is.EqualTo(@"")); } }
public void appending_multi_lines_with_a_prefix() { { StringBuilder b = new StringBuilder(); string text = @"First line. Second line. Indented. Also indented. Last line."; // Here, normalizing the source embedded string is to support // git clone with LF in files instead of CRLF. // Our (slow) AppendMultiLine normalizes the end of lines to Environment.NewLine. string t = b.AppendMultiLine("|", text, true).ToString(); t.Should().Be(@"|First line. |Second line. | Indented. | | Also indented. |Last line.".NormalizeEOL()); } { StringBuilder b = new StringBuilder(); string text = @"First line. Second line. Indented. Also indented. Last line."; string t = b.AppendMultiLine("|", text, false).ToString(); t.Should().Be(@"First line. |Second line. | Indented. | | Also indented. |Last line.".NormalizeEOL()); } }
public void appending_multi_lines_with_a_prefix_with_null_or_empty_or_one_line() { { StringBuilder b = new StringBuilder(); string text = @"One line."; string t = b.AppendMultiLine("|", text, true).ToString(); t.Should().Be(@"|One line."); } { StringBuilder b = new StringBuilder(); string text = @""; string t = b.AppendMultiLine("|", text, true).ToString(); t.Should().Be(@"|"); } { StringBuilder b = new StringBuilder(); string text = null; string t = b.AppendMultiLine("|", text, true).ToString(); t.Should().Be(@"|"); } { StringBuilder b = new StringBuilder(); string text = @"One line."; string t = b.AppendMultiLine("|", text, false).ToString(); t.Should().Be(@"One line."); } { StringBuilder b = new StringBuilder(); string text = @""; string t = b.AppendMultiLine("|", text, false).ToString();; t.Should().Be(@""); } { StringBuilder b = new StringBuilder(); string text = null; string t = b.AppendMultiLine("|", text, false).ToString(); t.Should().Be(@""); } }
static void DumpSecrets(UserKeyVault v) { string FirstPadding(bool missing) { return(missing ? "[Missing]" : " "); } string PaddingByDepth(int depth) => new string( ' ', depth * 5 ); void DoesThingWithGray(Action action) { var prev = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Gray; action(); Console.ForegroundColor = prev; } void WhitePipe() => DoesThingWithGray(() => Console.Write("│")); void RightArrow() { DoesThingWithGray(() => Console.Write("└────┬> ")); } foreach (var k in v.KeyStore.Infos) { if (k.SuperKey != null) { continue; } Console.ForegroundColor = k.IsSecretAvailable ? ConsoleColor.Green : ConsoleColor.Red; Console.Write(FirstPadding(!k.IsSecretAvailable)); WhitePipe(); Console.WriteLine(k.Name); Console.ForegroundColor = ConsoleColor.Gray; StringBuilder b = new StringBuilder(); b.AppendMultiLine(FirstPadding(false) + "│", k.Description, true, false); b.AppendLine(); Console.Write(b); var sub = k.SubKey; bool displayedAvailable = k.IsSecretAvailable; int depth = 0; while (sub != null) { if (sub.IsSecretAvailable) { Console.ForegroundColor = displayedAvailable ? ConsoleColor.DarkGreen : ConsoleColor.Green; displayedAvailable = true; } else { Console.ForegroundColor = ConsoleColor.Red; } Console.Write(FirstPadding(!sub.IsSecretAvailable)); Console.Write(PaddingByDepth(depth)); RightArrow(); Console.WriteLine(sub.Name); Console.ForegroundColor = ConsoleColor.Gray; depth++; b.Clear(); b.AppendMultiLine(FirstPadding(false) + PaddingByDepth(depth) + "│ ", sub.Description, true, false); b.AppendLine(); Console.Write(b.ToString()); sub = sub.SubKey; } Console.WriteLine(FirstPadding(false)); } }
/// <summary> /// Recursively dumps an <see cref="Exception"/> as readable text. /// </summary> /// <param name="w">The TextWriter to write to.</param> /// <param name="prefix">Prefix that will start all lines.</param> /// <param name="displayMessage">Whether the exception message must be displayed or skip.</param> /// <param name="ex">The exception to display.</param> static public void DumpException( StringBuilder w, string prefix, bool displayMessage, Exception ex ) { CKException ckEx = ex as CKException; if( ckEx != null && ckEx.ExceptionData != null ) { ckEx.ExceptionData.ToStringBuilder( w, prefix ); return; } string header = String.Format( " ┌──────────────────────────■ Exception : {0} ■──────────────────────────", ex.GetType().Name ); string p; w.AppendLine( prefix + header ); string localPrefix = prefix + " | "; if( displayMessage && ex.Message != null ) { w.Append( localPrefix + "Message: " ); w.AppendMultiLine( localPrefix + " ", ex.Message, false ); w.AppendLine(); } if( ex.StackTrace != null ) { w.Append( localPrefix + "Stack: " ); w.AppendMultiLine( localPrefix + " ", ex.StackTrace, false ); w.AppendLine(); } var fileNFEx = ex as System.IO.FileNotFoundException; if( fileNFEx != null ) { if( !String.IsNullOrEmpty( fileNFEx.FileName ) ) w.AppendLine( localPrefix + "FileName: " + fileNFEx.FileName ); #if NET451 || NET46 if( fileNFEx.FusionLog != null ) { w.Append( localPrefix + "FusionLog: " ); w.AppendMultiLine( localPrefix + " ", fileNFEx.FusionLog, false ); w.AppendLine(); } #endif } else { var loadFileEx = ex as System.IO.FileLoadException; if( loadFileEx != null ) { if( !String.IsNullOrEmpty( loadFileEx.FileName ) ) w.AppendLine( localPrefix + "FileName: " + loadFileEx.FileName ); #if NET451 || NET46 if( loadFileEx.FusionLog != null ) { w.Append( localPrefix + "FusionLog: " ); w.AppendMultiLine( localPrefix + " ", loadFileEx.FusionLog, false ); w.AppendLine(); } #endif } else { var typeLoadEx = ex as ReflectionTypeLoadException; if( typeLoadEx != null ) { w.AppendLine( localPrefix + " ┌──────────────────────────■ [Loader Exceptions] ■──────────────────────────" ); p = localPrefix + " | "; foreach( var item in typeLoadEx.LoaderExceptions ) { DumpException( w, p, true, item ); } w.AppendLine( localPrefix + " └─────────────────────────────────────────────────────────────────────────" ); } #if NET451 || NET46 else { var configEx = ex as System.Configuration.ConfigurationException; if( configEx != null ) { if( !String.IsNullOrEmpty( configEx.Filename ) ) w.AppendLine( localPrefix + "FileName: " + configEx.Filename ); } } #endif } } // The InnerException of an aggregated exception is the same as the first of it InnerExceptionS. // (The InnerExceptionS are the contained/aggregated exceptions of the AggregatedException object.) // This is why, if we are on an AggregatedException we do not follow its InnerException. var aggrex = ex as AggregateException; if( aggrex != null && aggrex.InnerExceptions.Count > 0 ) { w.AppendLine( localPrefix + " ┌──────────────────────────■ [Aggregated Exceptions] ■──────────────────────────" ); p = localPrefix + " | "; foreach( var item in aggrex.InnerExceptions ) { DumpException( w, p, true, item ); } w.AppendLine( localPrefix + " └─────────────────────────────────────────────────────────────────────────" ); } else if( ex.InnerException != null ) { w.AppendLine( localPrefix + " ┌──────────────────────────■ [Inner Exception] ■──────────────────────────" ); p = localPrefix + " | "; DumpException( w, p, true, ex.InnerException ); w.AppendLine( localPrefix + " └─────────────────────────────────────────────────────────────────────────" ); } w.AppendLine( prefix + " └" + new string( '─', header.Length - 2 ) ); }
/// <summary> /// Format the <paramref name="logEntry"/> /// </summary> /// <param name="logEntry"></param> /// <returns>A possible first entry - for monitor numbering - and the entry itself.</returns> public (FormattedEntry Before, FormattedEntry Entry) FormatEntry(IMulticastLogEntry logEntry) { FormattedEntry before = default; string formattedDate = GetFormattedDate(logEntry); char logLevel = logEntry.LogLevel.ToChar(); string indentationPrefix = ActivityMonitorTextHelperClient.GetMultilinePrefixWithDepth(logEntry.Text != null ? logEntry.GroupDepth : logEntry.GroupDepth - 1); if (!_monitorNames.TryGetValue(logEntry.MonitorId, out string?monitorId)) { string _monitorResetLog = ""; if (_monitorNames.Count - 1 == _maxMonitorCount) { ClearMonitorNames(); _monitorResetLog = $" Monitor reset count {_maxMonitorCount}."; } monitorId = B64ConvertInt(_monitorNames.Count); _monitorNames.Add(logEntry.MonitorId, monitorId); Debug.Assert(LogLevel.Info.ToChar() == 'i'); before = new FormattedEntry('i', indentationPrefix, monitorId, formattedDate, $" [] Monitor: ~{logEntry.MonitorId}. {_monitorResetLog}"); } string multiLinePrefix = _blankSpacePrefix + indentationPrefix; if (logEntry.Text != null) { Debug.Assert(logEntry.LogType != LogEntryType.CloseGroup); if (logEntry.LogType == LogEntryType.OpenGroup) { _builder.Append("> "); } _builder.Append(" [").Append(logEntry.Tags).Append("] "); multiLinePrefix += " "; _builder.AppendMultiLine(multiLinePrefix, logEntry.Text, false); if (logEntry.Exception != null) { _builder.AppendLine(); logEntry.Exception.ToStringBuilder(_builder, multiLinePrefix, false); } } else { Debug.Assert(logEntry.Conclusions != null); _builder.Append("< "); if (logEntry.Conclusions.Count > 0) { if (logEntry.Conclusions.Count == 1) { _builder.AppendMultiLine(multiLinePrefix + ' ', logEntry.Conclusions.Single().Text, false); } else { _builder.Append(logEntry.Conclusions.Count).Append(" conclusion"); if (logEntry.Conclusions.Count > 1) { _builder.Append('s'); } _builder.Append(':').AppendLine(); multiLinePrefix += ' '; bool first = true; foreach (var c in logEntry.Conclusions) { if (!first) { _builder.AppendLine(); } first = false; _builder.AppendMultiLine(multiLinePrefix + ' ', c.Text, true); } } } } string outputLine = _builder.ToString(); _builder.Clear(); return(before, new FormattedEntry(logLevel, indentationPrefix, monitorId, formattedDate, outputLine)); }
public void appending_multi_lines_with_a_prefix() { { StringBuilder b = new StringBuilder(); string text = @"First line. Second line. Indented. Also indented. Last line."; // Here, normalizing the source embedded string is to support // git clone with LF in files instead of CRLF. // Our (slow) AppendMultiLine normalizes the end of lines to Environment.NewLine. string t = b.AppendMultiLine( "|", text, true ).ToString(); Assert.That( t, Is.EqualTo( @"|First line. |Second line. | Indented. | | Also indented. |Last line.".NormalizeEOL() ) ); } { StringBuilder b = new StringBuilder(); string text = @"First line. Second line. Indented. Also indented. Last line."; string t = b.AppendMultiLine( "|", text, false ).ToString(); Assert.That( t, Is.EqualTo( @"First line. |Second line. | Indented. | | Also indented. |Last line.".NormalizeEOL() ) ); } }
public void appending_multi_lines_with_prefixLastEmptyLine() { string text = @"First line. Second line. "; { StringBuilder b = new StringBuilder(); string t = b.AppendMultiLine( "|", text, true, prefixLastEmptyLine: false ).ToString(); Assert.That( t, Is.EqualTo( @"|First line. |Second line. | |".NormalizeEOL() ) ); } { StringBuilder b = new StringBuilder(); string t = b.AppendMultiLine( "|", text, true, prefixLastEmptyLine: true ).ToString(); Assert.That( t, Is.EqualTo( @"|First line. |Second line. | | |".NormalizeEOL() ) ); } }
/// <summary> /// Writes a log entry (that can actually be a <see cref="IMulticastLogEntry"/>). /// </summary> /// <param name="e">The log entry.</param> public void Write(IMulticastLogEntry e) { Debug.Assert(DateTimeStamp.MaxValue.ToString().Length == 32, "DateTimeStamp FileNameUniqueTimeUtcFormat and the uniquifier: max => 32 characters long."); Debug.Assert(Guid.NewGuid().ToString().Length == 36, "Guid => 18 characters long."); BeforeWrite(); _builder.Append(' ', _nameLen + 32); _builder.Append("| ", e.Text != null ? e.GroupDepth : e.GroupDepth - 1); string prefix = _builder.ToString(); _builder.Clear(); // MonitorId (if needed) on one line. if (_currentMonitorId == e.MonitorId) { _builder.Append(' ', _nameLen + 1); } else { _currentMonitorId = e.MonitorId; if (!_monitorNames.TryGetValue(_currentMonitorId, out _currentMonitorName)) { _currentMonitorName = _monitorNames.Count.ToString("X" + _nameLen); int len = _currentMonitorName.Length; if (_nameLen < len) { prefix = " " + prefix; _nameLen = len; } _monitorNames.Add(_currentMonitorId, _currentMonitorName); _builder.Append(_currentMonitorName) .Append("~~~~") .Append(' ', 28) .Append("~~ Monitor: ") .AppendLine(_currentMonitorId.ToString()); _builder.Append(' ', _nameLen + 1); } else { _builder.Append(_currentMonitorName).Append('~'); _builder.Append(' ', _nameLen - _currentMonitorName.Length); } } // Log time prefixes the first line only. TimeSpan delta = e.LogTime.TimeUtc - _lastLogTime; if (delta >= TimeSpan.FromMinutes(1)) { string logTime = e.LogTime.TimeUtc.ToString(FileUtil.FileNameUniqueTimeUtcFormat); _builder.Append(' '); _builder.Append(logTime); _builder.Append(' '); _lastLogTime = e.LogTime.TimeUtc; } else { _builder.Append(' ', 17); _builder.Append('+'); _builder.Append(delta.ToString(@"ss\.fffffff")); _builder.Append(' '); } // Level is one char. char level; switch (e.LogLevel & LogLevel.Mask) { case LogLevel.Trace: level = ' '; break; case LogLevel.Info: level = 'i'; break; case LogLevel.Warn: level = 'W'; break; case LogLevel.Error: level = 'E'; break; default: level = 'F'; break; } _builder.Append(level); _builder.Append(' '); _builder.Append("| ", e.Text != null ? e.GroupDepth : e.GroupDepth - 1); if (e.Text != null) { if (e.LogType == LogEntryType.OpenGroup) { _builder.Append("> "); } prefix += " "; _builder.AppendMultiLine(prefix, e.Text, false).AppendLine(); if (e.Exception != null) { e.Exception.ToStringBuilder(_builder, prefix); } } else { Debug.Assert(e.Conclusions != null); _builder.Append("< "); if (e.Conclusions.Count > 0) { _builder.Append(" | ").Append(e.Conclusions.Count).Append(" conclusion"); if (e.Conclusions.Count > 1) { _builder.Append('s'); } _builder.Append(':').AppendLine(); prefix += " | "; foreach (var c in e.Conclusions) { _builder.AppendMultiLine(prefix, c.Text, true).AppendLine(); } } else { _builder.AppendLine(); } } _writer.Write(_builder.ToString()); AfterWrite(); _builder.Clear(); }
static StringBuilder AppendField( StringBuilder b, string prefix, string label, string text ) { b.Append( prefix ).Append( label ).Append( ": " ).Append( ' ', 10 - label.Length ); prefix += new string( ' ', 12 ); b.AppendMultiLine( prefix, text, false ).AppendLine(); return b; }
public void appending_multi_lines_to_empty_lines() { { StringBuilder b = new StringBuilder(); string text = Environment.NewLine; string t = b.AppendMultiLine( "|", text, true ).ToString(); Assert.That( t, Is.EqualTo( "|" ) ); } { StringBuilder b = new StringBuilder(); string text = Environment.NewLine + Environment.NewLine; string t = b.AppendMultiLine( "|", text, true ).ToString(); Assert.That( t, Is.EqualTo( "|" + Environment.NewLine + "|" ) ); } { StringBuilder b = new StringBuilder(); string text = Environment.NewLine + Environment.NewLine + Environment.NewLine; string t = b.AppendMultiLine( "|", text, true ).ToString(); Assert.That( t, Is.EqualTo( "|" + Environment.NewLine + "|" + Environment.NewLine + "|" ) ); } { StringBuilder b = new StringBuilder(); string text = Environment.NewLine + Environment.NewLine + Environment.NewLine + "a"; string t = b.AppendMultiLine( "|", text, true ).ToString(); Assert.That( t, Is.EqualTo( "|" + Environment.NewLine + "|" + Environment.NewLine + "|" + Environment.NewLine + "|a" ) ); } }
long PrefixWithOurExtension( Stopwatch w, string f, string[] results ) { GC.Collect(); w.Restart(); StringBuilder b = new StringBuilder(); for( int i = 0; i < results.Length; ++i ) { // We must use the prefixLastEmptyLine to match the way the naive implementation works. results[i] = b.AppendMultiLine( prefix, f, false, prefixLastEmptyLine: true ).ToString(); b.Clear(); } w.Stop(); return w.ElapsedTicks; }
/// <summary> /// Recursively dumps an <see cref="Exception"/> as readable text. /// </summary> /// <param name="w">The TextWriter to write to.</param> /// <param name="prefix">Prefix that will start all lines.</param> /// <param name="displayMessage">Whether the exception message must be displayed or skip.</param> /// <param name="ex">The exception to display.</param> static public void DumpException(StringBuilder w, string prefix, bool displayMessage, Exception ex) { CKException ckEx = ex as CKException; if (ckEx != null && ckEx.ExceptionData != null) { ckEx.ExceptionData.ToStringBuilder(w, prefix); return; } string header = String.Format(" ┌──────────────────────────■ Exception : {0} ■──────────────────────────", ex.GetType().Name); string p; w.AppendLine(prefix + header); string localPrefix = prefix + " | "; if (displayMessage && ex.Message != null) { w.Append(localPrefix + "Message: "); w.AppendMultiLine(localPrefix + " ", ex.Message, false); w.AppendLine(); } if (ex.StackTrace != null) { w.Append(localPrefix + "Stack: "); w.AppendMultiLine(localPrefix + " ", ex.StackTrace, false); w.AppendLine(); } var fileNFEx = ex as System.IO.FileNotFoundException; if (fileNFEx != null) { if (!String.IsNullOrEmpty(fileNFEx.FileName)) { w.AppendLine(localPrefix + "FileName: " + fileNFEx.FileName); } #if NET451 || NET46 if (fileNFEx.FusionLog != null) { w.Append(localPrefix + "FusionLog: "); w.AppendMultiLine(localPrefix + " ", fileNFEx.FusionLog, false); w.AppendLine(); } #endif } else { var loadFileEx = ex as System.IO.FileLoadException; if (loadFileEx != null) { if (!String.IsNullOrEmpty(loadFileEx.FileName)) { w.AppendLine(localPrefix + "FileName: " + loadFileEx.FileName); } #if NET451 || NET46 if (loadFileEx.FusionLog != null) { w.Append(localPrefix + "FusionLog: "); w.AppendMultiLine(localPrefix + " ", loadFileEx.FusionLog, false); w.AppendLine(); } #endif } else { var typeLoadEx = ex as ReflectionTypeLoadException; if (typeLoadEx != null) { w.AppendLine(localPrefix + " ┌──────────────────────────■ [Loader Exceptions] ■──────────────────────────"); p = localPrefix + " | "; foreach (var item in typeLoadEx.LoaderExceptions) { DumpException(w, p, true, item); } w.AppendLine(localPrefix + " └─────────────────────────────────────────────────────────────────────────"); } #if NET451 || NET46 else { var configEx = ex as System.Configuration.ConfigurationException; if (configEx != null) { if (!String.IsNullOrEmpty(configEx.Filename)) { w.AppendLine(localPrefix + "FileName: " + configEx.Filename); } } } #endif } } // The InnerException of an aggregated exception is the same as the first of it InnerExceptionS. // (The InnerExceptionS are the contained/aggregated exceptions of the AggregatedException object.) // This is why, if we are on an AggregatedException we do not follow its InnerException. var aggrex = ex as AggregateException; if (aggrex != null && aggrex.InnerExceptions.Count > 0) { w.AppendLine(localPrefix + " ┌──────────────────────────■ [Aggregated Exceptions] ■──────────────────────────"); p = localPrefix + " | "; foreach (var item in aggrex.InnerExceptions) { DumpException(w, p, true, item); } w.AppendLine(localPrefix + " └─────────────────────────────────────────────────────────────────────────"); } else if (ex.InnerException != null) { w.AppendLine(localPrefix + " ┌──────────────────────────■ [Inner Exception] ■──────────────────────────"); p = localPrefix + " | "; DumpException(w, p, true, ex.InnerException); w.AppendLine(localPrefix + " └─────────────────────────────────────────────────────────────────────────"); } w.AppendLine(prefix + " └" + new string( '─', header.Length - 2 )); }