我有以下代码:
catch(Exception ex)
{
throw new FatalException("An error occurred while trying to load the XSLT file.", ex);
}
不幸的是,这只是吞噬了异常。我可以通过执行以下操作来解决此问题:
catch(Exception ex)
{
throw;
}
但是我仍然想要包含自定义消息以获取事件记录的帮助。
如何在不丢失任何信息的情况下将此消息添加到例外? (堆栈跟踪/调试符号等)
答案 0 :(得分:63)
如果您只需要向原始异常添加信息,例如用户可读的消息或对您追踪错误但对最终用户没用的特定详细信息,您可以使用Exception的Data属性,这是一个键/值对字典。
我们广泛使用它来记录诸如正在执行的报告或正在处理的文件之类的信息,以便操作可以确定错误发生时到底发生了什么。用户不需要此详细信息,因为他们直接处理故障原因。
您还可以使用它来传递对用户有意义的纯文本消息。唯一的问题是您必须在日志框架或最终用户界面中执行一些额外的工作,以便提取数据并使其对消费者有用。
例如,你可以这样做:
catch (Exception ex)
{
ex.Data.Add("UserMessage", "An error occurred while trying to load the XSLT file.");
throw;
}
然后在客户端代码中,您可以测试以查看UserMessage是否存在,如果存在,则将其呈现给用户而不是Exception:
catch (Exception ex)
{
if (ex.Data.Contains("UserMessage"))
{
MessageBox.Show(ex.Data["UserMessage"].ToString());
}
else
{
MessageBox.Show(ex.Message);
}
}
答案 1 :(得分:15)
原来的异常仍在那里。
当您执行异常日志记录时,您收到的异常将是您使用消息进行的FatalException。原始异常位于ex.InnerException
。您可以继续循环遍历InnerException,直到它为null,以获取所有堆栈跟踪信息等。
答案 2 :(得分:1)
总之,不要。
我相信你可以通过一些反思找到解决问题的方法,但我会强烈警告你不要这样做。它违背了.NET中异常的原始设计。例外不仅仅是帮助记录,它们提供有关应用程序失败的原始原因的信息。
通常首选使用第一个选项,因为它维护原始异常的堆栈跟踪,但允许您通过将其包装在单独的异常中来提供其他信息。在我自己的代码中,每当我记录异常时,我的日志记录函数将通过InnerException属性进行递归,以找到有关错误的每一点有用信息。
答案 3 :(得分:0)
以防万一有人需要一个好的答案。关键是使用AppDomain.CurrentDomain.FirstChanceException
您可以创建一个具有IDisposable的自定义对象,以将所有信息放入其中。如果发生异常,则FirstChanceException处理程序将获取该信息并填充Exception.Data。
使用本地线程存储来使其成为线程安全。然后,捕获它的代码将获取数据并记录下来。
示例:
using(MyCustomMessage.EnterToLocalStorage("Info for logging"") )
{
...code
...exception thrown
.... FirstChanceException examines local thread storage and get's "info for logging" and puts into Exception.Data.
}
//Dispose is called and all messages that were put into LocalStorage are removed.
//So if exception was not thrown before then it like nothing happened.
Google AsyncDiagnosticStack就是一个很好的例子。 https://github.com/StephenCleary/AsyncDiagnostics/blob/master/src/Nito.AsyncEx.AsyncDiagnostics/AsyncDiagnosticStack.cs