使用HttpModule进行异常处理

时间:2020-03-06 14:42:53  来源:igfitidea点击:

我们正在审查该公司系统的异常处理之一,发现了一些有趣的事情。

大多数代码块(如果不是全部的话)都在try / catch块中,并且在catch块中引发了新的BaseApplicationException,该异常似乎来自企业库。
我在这里有点麻烦,因为我看不到这样做的好处。 (任何时候发生都会引发另一种异常)
使用该系统已有一段时间的一位开发人员说,这是因为该类负责发布异常(发送电子邮件和类似的东西),但是他不太确定。
在花了一些时间看完代码之后,我很有信心地说,这就是收集有关环境的信息,而不是发布它。

我的问题是:
将所有代码包装在try {} catch {}块中并抛出新异常是否合理?如果是的话,为什么呢?有什么好处?

我个人的观点是,使用HttpModule,注册Application事件的Error事件以及执行模块内部所需的操作会容易得多。如果我们走这条路,我们会错过什么吗?有什么缺点吗?

非常感谢意见。

解决方案

我来自一个思想流派,应该使用try / catch块,并且不要抛出异常。如果我们正在执行的代码很可能会出错,则应该对其进行处理,记录并返回某些内容。重新抛出异常仅是为了在应用程序生命周期的后期重新记录日志。

这是有关如何使用HttpModule处理异常的有趣文章:http://blogs.msdn.com/rahulso/archive/2008/07/13/how-to-use-httpmodules-to-troubleshoot-your-asp- net-application.aspx和http://blogs.msdn.com/rahulso/archive/2008/07/18/asp-net-how-to-write-error-messages-into-a-text-file-using-一个简单的httpmodule.aspx

看看ELMAH。它可以满足要求。很好。

创建库时,我总是尝试减少调用者要处理的异常数量。例如,考虑连接到sql数据库的存储库组件。从理论上讲,从sql客户端异常到无效的强制转换异常,都有大量的异常可以抛出。其中许多文件都有明确记录,可以在编译时解决。因此,我会尽可能多地捕获它们,将它们放在单个异常类型中,例如RepositoryException,然后让该异常汇总到调用堆栈中。

原始异常得以保留,因此可以对原始异常进行诊断。但是我的调用者只需要担心处理单个异常类型,而不用用大量不同的catch块来填充代码。

当然,这有一些问题。最值得注意的是,如果调用者可以处理其中一些异常,则它们必须在RepositoryException中扎根,然后打开内部异常的类型来处理它。它比为单个异常类型具有单个catch块还不够干净。但是,我认为这并不是什么大问题。

听起来像抛出的异常不应作为异常实现。

无论如何,我要说的是,由于此BaseApplicationException是通用的通用异常,因此最好抛出更特定于上下文的异常。因此,当我们尝试从数据库中检索实体时,可能需要EntityNotFoundException。这样,在调试时,我们不必搜索内部异常和堆栈跟踪即可发现真正的问题。如果此BAseApplicationException正在收集有关异常的信息(例如跟踪内部异常),那么这应该不是问题。

仅当我无法更接近代码中实际发生异常的位置时,才使用HttpModule。我们实际上并不需要依赖于BaseApplicationexception的错误信息的HttModule OnError事件,它是一个巨大的switch语句。

总而言之,当我们可以给出更具体的例外情况以立即告诉我们问题的根源时,值得抛出不同的例外情况。

根据我的经验,捕获异常,然后将错误添加到Server(?)对象。这将使.NET可以执行所需的任何操作,然后显示异常。

如果我正确地阅读了这个问题,我会说实现一个try / catch来拦截异常(我们不会提到是捕获所有异常,还是捕获特定异常?)并抛出不同的异常通常是一件坏事。

缺点:

至少我们将丢失堆栈跟踪信息,我们将看到的堆栈只会扩展到引发新异常的方法,因此我们可能会在此处丢失一些良好的调试信息。

如果捕获到Exception,则冒着掩盖关键异常(例如OutOfMemory或者StackOverflow)的风险,使其具有不太关键的异常的风险,从而使进程继续运行,可能应该将其拆除。

可能的优势:

在某些非常特定的情况下,我们可以采用一个调试值不高的异常(例如某些异常从数据库返回),并包装一个异常,该异常会添加更多上下文,例如我们正在处理的对象的id。

但是,在几乎所有情况下,这都是难闻的气味,应谨慎使用。

通常,只有在该位置可以执行一些实际操作(例如恢复,回滚,计划B等)时,我们才应该捕获异常。如果我们无能为力,请允许它向上移动。仅当该位置有可用的特定且有用的数据可以增加原始异常并因此有助于调试时,才应捕获并引发新异常。

Never1catch(ex ex例外)。期间2. 我们无法处理所有可能遇到的各种错误。

如果我们无法处理或者提供其他信息(供后续异常处理程序使用),则Never3会捕获异常派生的类型。显示错误消息与处理错误不同。

出于以下原因,有两个原因:

  • 捕捉和重新抛出很昂贵
  • 我们最终将失去堆栈跟踪
  • 代码中的信噪比会很低

如果我们知道如何处理特定的异常(并将应用程序重置为错误前状态),请捕获该异常。 (这就是为什么将其称为异常处理的原因。)

要处理未捕获的异常,请侦听适当的事件。在执行WinForms时,我们需要侦听System.AppDomain.CurrentDomain.UnhandledException,如果在执行ThreadingSystem.Windows.Forms.Application.ThreadException。 System.Web.HttpApplication.Error`)。

至于在应用程序中包装框架异常(非特定异常)(即抛出新的MyBaseException(ex);):毫无意义,而且气味难闻.4

编辑

1从来没有一个苛刻的词,尤其是在工程方面,正如@Chris在评论中指出的那样。当我第一次写这个答案时,我会承认自己精通原则。

2,3参见1.

4如果我们不带任何新东西,我仍然支持。如果我们将" Exception ex"作为方法的一部分捕获,并且我们知道它可能会以多种方式失败,那么我相信当前方法应该在其签名中反映出来。如我们所知,异常不是方法签名的一部分。