internal static string GetDetailedExceptionMessage(this Exception ex, bool forUser) { // Must handle EVException separately otherwise its ToString would call us again and cause infinite recursion if (ex is EVException) { return(String.Empty); } if (forUser) { // Suppress default message CLR produces if no message is specified in exception string realMessage = MessageFieldInfo.GetValue(ex) as string; if (String.IsNullOrWhiteSpace(realMessage)) { return(String.Empty); } } // Debugging //FieldInfo[] exceptionFields = typeof(Exception).GetFields(BindingFlags.NonPublic | BindingFlags.Instance); // Save InnerException so we can restore it back Exception innerException = ex.InnerException; // Reset InnerException so that ToString() would not go recursive InnerExceptionFieldInfo.SetValue(ex, null); // Save StackTraceString so we can restore it back object strStackTraceString = StackTraceStringFieldInfo.GetValue(ex); // Reset strStackTraceString to empty string so that it would not show up in ToString() output StackTraceStringFieldInfo.SetValue(ex, String.Empty); // Getting single level (non-recursive) ToString() without StackTrace string detailedExceptionMessage = ex.ToString(); if (forUser) { // End users are not interested to see the type of exception being thrown. Unfortunately most system exceptions tend to // prepend it in their implementation of ToString() overload. string typePrefix = ex.GetType().FullName + ": "; detailedExceptionMessage = Utils.RemovePrefix(detailedExceptionMessage, typePrefix); } detailedExceptionMessage = Utils.RemoveSuffix(detailedExceptionMessage, "\r\n"); IOException ioEx = ex as IOException; if (ioEx != null && !ex.GetOrCreatePayload().ContainsProperty(FileNameLabel)) { object objFileName = MaybeFullPathFieldInfo.GetValue(ioEx); string fileName = objFileName == null ? "Unknown" : objFileName.ToString(); ex.AddNamedProperty(FileNameLabel, fileName); } // Restoring InnerException and StackTrace back to their original values InnerExceptionFieldInfo.SetValue(ex, innerException); StackTraceStringFieldInfo.SetValue(ex, strStackTraceString); return(detailedExceptionMessage); }