/// <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> /// Creates a <see cref="CKExceptionData"/> from any <see cref="Exception"/>. /// </summary> /// <param name="ex">Exception for which data must be created. Can be null: null is returned.</param> /// <returns>The data that describes the exception.</returns> static public CKExceptionData CreateFrom(Exception ex) { if (ex == null) { return(null); } CKException ckEx = ex as CKException; if (ckEx != null) { return(ckEx.EnsureExceptionData()); } Type t = ex.GetType(); string exceptionTypeName = t.Name; string exceptionTypeAssemblyQualifiedName = t.AssemblyQualifiedName; CKExceptionData innerException; CKExceptionData[] aggregatedExceptions = null; var aggEx = ex as AggregateException; if (aggEx != null) { CKExceptionData[] a = new CKExceptionData[aggEx.InnerExceptions.Count]; for (int i = 0; i < a.Length; ++i) { a[i] = CreateFrom(aggEx.InnerExceptions[i]); } innerException = a[0]; aggregatedExceptions = a; } else { innerException = CreateFrom(ex.InnerException); } string fileName = null; string detailedInfo = null; CKExceptionData[] loaderExceptions = null; var typeLoadEx = ex as ReflectionTypeLoadException; if (typeLoadEx != null) { CKExceptionData[] a = new CKExceptionData[typeLoadEx.LoaderExceptions.Length]; for (int i = 0; i < a.Length; ++i) { a[i] = CreateFrom(typeLoadEx.LoaderExceptions[i]); } loaderExceptions = a; } else { var fileNFEx = ex as System.IO.FileNotFoundException; if (fileNFEx != null) { fileName = fileNFEx.FileName; #if NET451 || NET46 detailedInfo = fileNFEx.FusionLog.NormalizeEOL(); #endif } else { var loadFileEx = ex as System.IO.FileLoadException; if (loadFileEx != null) { fileName = loadFileEx.FileName; #if NET451 || NET46 detailedInfo = loadFileEx.FusionLog.NormalizeEOL(); #endif } else { #if NET451 || NET46 var configEx = ex as System.Configuration.ConfigurationException; if (configEx != null) { fileName = configEx.Filename; } #endif } } } return(new CKExceptionData(ex.Message, exceptionTypeName, exceptionTypeAssemblyQualifiedName, ex.StackTrace, innerException, fileName, detailedInfo, loaderExceptions, aggregatedExceptions)); }