使用HttpModule进行exception处理

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

大多数代码块(如果不是全部)都在try / catch块中,并且在catch块内部抛出了一个新的BaseApplicationException – 它似乎来自企业库。 我在这里遇到了一些麻烦,因为我没有看到这样做的好处。 (在任何时候发生另一个例外)其中一个开发人员一直在使用该系统说这是因为该类负责发布exception(发送电子邮件和类似的东西),但他不太确定。 在花了一些时间浏览代码之后,我非常有信心地说,这就是收集有关环境的信息而不是发布它。

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

我个人认为,使用HttpModule会更容易,注册Application事件的Error事件,并在模块内部执行必要的操作。 如果我们走这条路,我们会错过什么吗? 有什么缺点吗?

您的意见非常感谢。

从不 catch (Exception ex) 。 期间2 。 您无法处理可能遇到的所有不同类型的错误。

如果您无法处理或提供其他信息(由后续exception处理程序使用),则永远不要捕获exception派生类型。 显示错误消息与处理错误不同。

从我的头脑中可以看出几个原因:

  • 捕捉和重新抛弃是昂贵的
  • 你最终会失去堆栈跟踪
  • 您的代码中的信号与噪声比率较低

如果您知道如何处理特定exception(并将应用程序重置为错误前状态),请捕获它。 (这就是为什么它被称为exception 处理 。)

要处理未捕获的exception,请侦听相应的事件。 在执行WinForms时,您需要侦听System.AppDomain.CurrentDomain.UnhandledException ,并且 – 如果您正在执行ThreadingSystem.Windows.Forms.Application.ThreadException. 对于Web应用程序,有类似的机制( System.Web.HttpApplication.Error )。

至于在应用程序(非)特定exception中包装框架exception(即throw new MyBaseException(ex); ):完全没有意义,并且有难闻的气味。 4


编辑

1 @Chris在评论中指出, 从来不是一个非常严厉的词,特别是涉及到工程学。 当我第一次写这个答案时,我会承认我的原则很高。

2,31

4如果你没有带来任何新的东西,我仍然坚持这一点。 如果您已经将Exception ex作为您知道可能以多种方式失败的方法的一部分,我相信当前的方法应该反映出它的签名。 如您所知,exception不是方法签名的一部分。

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

缺点:

至少你会丢失堆栈跟踪信息 – 你将看到的堆栈只会扩展到抛出新exception的方法 – 你可能会丢失一些好的调试信息。

如果您正在捕获exception,那么您将面临着屏蔽关键exception的风险,例如OutOfMemory或StackOverflow具有不太严重的exception,从而使进程保持运行,可能它应该被拆除。

可能的优点:

在一些非常特殊的情况下,您可以采用一个没有太多调试值的exception(比如从数据库返回的一些exception)并使用exception包装,这会添加更多上下文,例如您正在处理的对象的id。

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

一般情况下,当你在那个地方有一些现实的东西时,你应该只抓住一个例外 – 即恢复,回滚,计划B等。如果没有什么可以做的,就让它通过链条。 如果该位置有可用的特定有用数据可以增加原始exception并因此有助于调试,那么您应该只捕获并抛出一个新exception。

我来自思想学派,应该使用try / catch块,而不是重新抛出exception。 如果您执行的代码很可能出错,那么应该处理,记录并返回一些代码。 重新抛出exception仅用于稍后在应用程序生命周期中重新记录。

这是一篇关于如何使用HttpModule处理exception的有趣post: 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- A-简单httpmodule.aspx

看看ELMAH 。 它做你正在谈论的事情。 很好。

当我创建库时,我尝试始终为调用者提供减少数量的exception来处理。 例如,考虑一个连接到sql数据库的Repository组件。 从理论上可以抛出从sql客户端exception到无效强制转换exception的exception。 其中许多都是清楚记录的,可以在编译时进行说明。 所以,我尽可能多地捕获它们,将它们放在一个exception类型中,例如RepositoryException,并让该exception汇总调用堆栈。

保留原始exception,因此可以诊断原始exception。 但是我的调用者只需要担心处理一个exception类型而不是用大量不同的catch块来丢弃它们的代码。

当然,这有一些问题。 最值得注意的是,如果调用者可以处理其中一些exception,他们必须在RepositoryException中查找,然后打开内部exception的类型来处理它。 它比单个exception类型的单个catch块更不干净。 但是,我不认为这是一个很大的问题。

听起来像抛出的exception不应该作为例外实现。

无论如何,我会说,因为这个BaseApplicationException是一个通用的多用途exception,所以抛出更具特定于上下文的exception会更好。 因此,当您尝试从数据库中检索实体时,您可能需要EntityNotFoundException。 这样,在进行调试时,您不必搜索内部exception和堆栈跟踪来查找真正的问题。 如果此BAseApplicationException正在收集有关exception的信息(如跟踪内部exception),那么这应该不是问题。

只有当我无法接近代码中实际发生exception的地方时,我才会使用HttpModule。 根据BaseApplicationexception的错误信息,你真的不希望HttModule OnError事件是一个巨大的switch语句。

总而言之,当您可以提供更具体的exception时,可以抛出不同的exception,从而直接告诉您问题的根源。

根据我的经验,捕获exception,将错误添加到Server(?)对象。 这将允许.NET执行它需要做的事情,然后显示您的exception。