繁体   English   中英

使用HttpModule进行异常处理

[英]Exception handling using an HttpModule

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

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

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

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

您的意见非常感谢。

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

从未3捕捉异常衍生的类型,如果你不能处理它或提供额外的信息(由随后的异常处理程序中使用)。 显示错误消息是一样的处理错误。

有几个原因,从我的头脑中:

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

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

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

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


编辑

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

2,31

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

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

缺点:

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

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

可能的优点:

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

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

一般情况下,只有当你在那个位置可以做一些现实的事情时才能发现异常 - 即恢复,回滚,计划B等。如果你无能为力,只需让它通过链条。 如果该位置有可用的特定和有用数据可以增加原始异常并因此有助于调试,那么您应该只捕获并抛出一个新异常。

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

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

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

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

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

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

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM