抛出异常但保留堆栈跟踪信息

6

我想抛出一个异常,但是需要自定义消息并保留堆栈信息。我查阅了各种帖子。

catch (Exception ex)
{
throw; // Message is read only but stacktrace persist
throw ex; // Message is readonly and strack trace also blows .. worst!
throw new CustomException("My exception");// Message can be overridden but stacktrace lost
throw new CustomException("My message",ex);// same as above. However if this constructor in exception class calls same constructor of base class then .. see below
}

当使用最后一种方法(使用自定义异常构造函数调用基类构造函数)时,死亡屏幕上的输出如下:
**The remote server returned an error: (401) Unauthorized.**

[WebException: The remote server returned an error: (401) Unauthorized.]
original stack trace 

[NewException: newMessage]
New  Stack Trace

好的事情是一切都在屏幕上显示。但是,我希望在顶部显示我的异常,即“新消息”,而不是原始消息。

因此,我要解决的问题是:如何在死机屏幕上显示原始堆栈跟踪,但带有自定义错误消息?


1
这是一个返回异常的 Web 服务吗? - Oded
在我的例子中,确实是一个Web服务调用。然而,这并不重要,因为异常可能是任何东西,比如除零或sqlException等。想法是让用户知道原始堆栈跟踪,但开发人员也可以将默认异常消息定制为更有帮助的消息。 - helloworld
不,这并不是无关紧要的。Web服务框架对异常有自己的想法。 - H H
4个回答

8
 throw new CustomException("My message",ex);// same as above (... stacktrace lost)

在最后一个评论中,您的结论是错误的。堆栈跟踪保存在内部异常中。标准报告(包括 Exception.ToString() )将报告完整的堆栈跟踪。当您正确调用构造函数时,这就是您看到的情况。(始终调用正确的基础构造函数!)

但我不认识 [WebException] 。在 WCF 中,您需要

  <serviceDebug includeExceptionDetailInFaults="true"/>   

我猜你的Web环境具有类似的功能,可以抑制向客户端传递错误信息。

3
使用第四种方法是通常做法和已经建立的模式。你不应该将异常处理(或抛出)与它们如何显示或记录混淆。
如果你可以控制(捕获的)异常的输出,即可以更改/编写相应的代码,那么你可以简单地使用 Exception.ToString() 方法,它会打印外部异常,包括所有“内部”异常。
备注:有时应用程序故意不显示内部异常。例如,在WCF(Windows Communication Foundation)中,除非设置了 IncludeExceptionDetails(通过配置、代码等...),否则内部异常甚至不会从服务器传输到客户端。这通常是因为内部异常被认为是一个实现细节,可能为攻击者提供有价值的信息来破坏你的应用程序。

0

覆盖 StackTrace 属性怎么样?

class CustomException : Exception {

    public CustomException(string message, Exception inner) : base(message, inner) {
    }

    public override string StackTrace {
        get {
            if (InnerException != null) {
                return InnerException.StackTrace;
            }
            return base.StackTrace;
        }
    }
}

尝试了一下... 在显示黄屏幕死机时,断点返回InnerException.Stacktrace被调用三次,每次都显示原始堆栈跟踪。但奇怪的是它仍然显示新的堆栈跟踪:( - helloworld
@enableDeepak:不知道这会导致宇宙自我崩溃...抱歉 :( - Paolo Tedesco

0

我同意,通常情况下选项4是最好的...

然而,在开发过程中,我发现将整个catch子句放在#if (!DEBUG)内非常有用,而finally则在其外面(以允许在调试模式下编译):

#if (!DEBUG)
catch (Exception ex)
{
    // Catch logic for Release mode
}
#endif
finally { }

这样做使得API在错误发生的位置中断,而不是在顶层中断。

只是不要养成在几乎所有其他情况下使用#if的习惯,使用...即可。

[Conditional("DEBUG")]

在方法前面


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接