在C#.NET中捕获所有未处理的异常的简单方法

31

我有一个使用C#.NET构建的网站,经常会从各种用户控件产生相当稳定的SQL超时,并且我想轻松地添加一些代码来捕获所有未处理的异常并将它们发送到可以记录它们并向用户显示友好消息的某个位置。

如何通过最小的努力捕获所有未处理的异常?

这个问题似乎说这是不可能的,但这对我来说没有意义(而且它是关于在Windows应用程序中使用.NET 1.1的):


4
这不是治标不治本吗?也就是说,你应该通过在数据库服务器上运行SQL Profiler跟踪来查找SQL超时的根本原因,对症下药,而不是只是对症疗法。 - Mitch Wheat
1
我认为你需要澄清一下“catch”的含义:是指可以处理异常的try..catch,还是仅希望被告知发生了未处理的异常,并记录何时/何处(例如ELMAH)。 - Robert Paulson
你能把其中一个答案标记为正确答案吗? - ceztko
13个回答

28

所有未处理的异常最终都会通过 global.asax 中的 Application_Error 进行传递。因此,要提供一般性的异常消息或进行日志记录操作,请参见 Application_Error


10
我有一个用C#.NET构建的网站,它倾向于... - Ali Ersöz
3
帮助理解上一个评论的人们 - 我猜它是在回答一个已被删除的评论。(提示:看看谁写的回答和谁写的评论。) - ispiro
您可能需要在web.config中设置<customErrors mode="Off"/>。如果没有这个条目,它在生产服务器上无法正常工作。 - ghord

16

如果您需要在所有线程中捕获异常,最好的方法是实现UnhandledExceptionModule并将其添加到您的应用程序,请查看此处示例。


这个问题涉及到Windows应用程序,而不是Web应用程序。 - HTTP 410
13
我有一个用C#.NET构建的网站。 - annakata

15
在您的Global.asax文件中使用Application_Error方法。在Application_Error方法实现中调用Server.GetLastError(),以任何您想要的方式记录由Server.GetLastError()返回的异常的详细信息。
例如:
void Application_Error(object sender, EventArgs e) 
{ 
    // Code that runs when an unhandled error occurs
    log4net.ILog log = log4net.LogManager.GetLogger(typeof(object));
    using (log4net.NDC.Push(this.User.Identity.Name))
    {
        log.Fatal("Unhandled Exception", Server.GetLastError());
    }
}

不要过多关注log4net的内容,Server.GetLastError()是最有用的部分,但是记录详细信息可以按照您喜欢的方式进行。


对我来说,我还必须在我的Web.config中设置customErrors模式为Off <customErrors mode="Off" />。否则它仍然无法工作。不幸的是,我没有意识到这是必需的。有些东西告诉我我需要更仔细地查找和阅读文档。 - DankMemester 'Andrew Servania'

8

ELMAH项目听起来值得一试,其特性包括:

ELMAH (Error Logging Modules and Handlers)是一个应用程序范围内完全可插拔的错误日志记录设施。可以动态地将它添加到正在运行的ASP.NET Web应用程序,甚至是机器上的所有ASP.NET Web应用程序中,而无需重新编译或重新部署。

  • 记录几乎所有未处理的异常。
  • 远程查看记录的异常的全部日志的Web页面。
  • 远程查看任何一个已记录异常的详细信息的Web页面。
  • 在许多情况下,即使customErrors模式关闭,也可以查看由ASP.NET为给定异常生成的原始黄屏。
  • 每次错误发生时都会收到电子邮件通知。
  • 日志中最后15个错误的RSS源。
  • 多种日志基础存储实现。

有关使用ELMAH的更多信息,请参见dotnetslackers


7
您可以订阅AppDomain.CurrentDomain.UnhandledException事件。

从2.00版本开始,这个程序不会捕获异常,只是提供了记录日志的机会。但在1.0->1.1版本中确实有这个功能,但这是在2.00版本中修复的一个错误。我认为你还需要使用Application.ThreadException或类似的东西来完全覆盖。 - Quibblesome
同意,但是OP的意图似乎是用于记录和重定向,而不是陷阱。Application.ThreadException适用于WinForms,而不是WebForms。 - P Daddy
我认为Quarrelsome是正确的,因为OP的问题涉及Windows应用程序而不是Web应用程序。 - HTTP 410
4
“我有一个用C#.NET构建的网站。” - P Daddy
2
我确实在谈论一个Web应用程序。 - adambox

3

需要注意的是,你不应该捕获未处理的异常。如果你遇到了 SQL 超时问题,应该专门捕获这些异常。


你的观点“重要的是要注意不应该捕获未处理的异常”是完全不合逻辑的(没有参考,原因等)。此外,你听说过throw语句吗? - Kelly Elton
我会提供更多信息。微软不希望你捕获(Exception)。否则,你将无法通过Windows标志认证。你也不应该抛出新的Exception,通常应该抛出ApplicationException。你总是应该捕获最具体的异常,这是有意义的。 - Adam Tegen
1
捕捉所有异常,将其记录并抛出是有用的。我认为人们最糟糕的做法是在所有代码周围都加上try-catch,甚至更糟糕的是基于try-catch进行语音控制流。例如,我有一个程序,它附加到UnhandledException的委托,因此每当有任何未处理的异常时,我都会收到异常。然后我将其提交给Web服务,并让我的软件崩溃。否则你怎么知道出了什么问题呢? - Kelly Elton
抱歉,我应该把我的想法说完整。只要你重新抛出异常,你就没问题了。catch(exception e){ log(e); }是不好的。catch(exception e){ log(e); throw; }是可以的。 - Adam Tegen

2

您的意思是处理所有线程,包括由第三方代码创建的线程吗?在“已知”的线程中,只需在堆栈顶部捕获 Exception


1
我建议看一下log4net,看看它是否适合问题的日志记录部分。

1

1

这个问题有两个部分,处理和识别。

识别

当异常最终被捕获时,这就是你所做的事情,不一定是它抛出的地方。因此,在那个阶段,异常必须具有足够的上下文信息,以便您可以确定问题所在。

处理

对于处理,您可以:

a) 添加一个 HttpModeule。请参见http://www.eggheadcafe.com/articles/20060305.asp。我建议仅在绝对没有上下文信息可用且可能存在 IIS/aspnet 问题的灾难性情况下采用此方法。

b) 创建一个名为 AbstractBasePage 的抽象类,该类派生自 Page 类,并使所有代码后台类都派生自 AbstractBasePage。

AbstractBasePage 可以实现 Page.Error 委托,以便可以在此处捕获(并可能记录)通过 n 层架构上升的所有异常。

我建议针对你所谈论的异常类型(如SQLException),有足够的上下文信息可以让你识别它是一个超时,并采取可能的行动。这些行动可能包括将用户重定向到具有适当消息的自定义错误页面,以处理每种不同类型的异常(如Sql、Web服务、异步调用超时等)。
谢谢 RVZ

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