如何处理异常并在asp.net中进行处理的最佳方法是什么?

3
首先,我已经熟悉了简单的异常处理语法,但我想知道处理它们的最佳位置、最佳时间和最佳方式。
我正在构建一个N层应用程序。因此,我认为DAL有时会生成一些需要处理的错误...我刚学习了SqlException类,那个类是什么?我曾经看到过一个处理SqlException然后处理Exception的代码!
在了解实践和我要处理它们的地方之后,我计划创建一个连接到数据库并将错误记录在数据库中以便我可以修复它的方法,但我仍然不知道应该收集哪些信息来让我识别整个情况!
我以为异常处理不是什么大不了的事情。但是每隔一段时间,我就会读到一些奇怪的建议-我从未理解过-在问题评论中,但由于这是一些非常古老的问题,没有人能回答我!

“不要只是显式地捕获异常”

“在您的应用程序中使用的高层代码必须始终只抛出异常,而不用担心如何处理它们。”

编辑

Page_Error事件和Application_Error呢?我看到它们是处理错误的好方法。


2
以下是关于在.NET应用程序中处理异常的一些好建议:http://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx - Jeffrey L Whitledge
5个回答

8

异常处理是一项重大任务,设计一个好的策略并不简单。

首先,有一些通用规则:

  • 当运行代码无法继续时会发生异常,所以也许它试图处理一些内部异常但最终失败了。想想TCP连接:如果损坏的数据包到达,则为异常,但TCP协议可以处理它。如果有太多数据包损坏,则会抛出I/O或套接字异常。
  • 异常并不总是可以被处理。几乎在所有情况下,当您从底层层次收到异常时,就无法运行纠正性代码。如果您的应用程序依赖于离线的DB,并且您得到了关于它的异常,那么您只能显示错误消息。
  • 异常可能是意外的,并可能暴露设计或实现缺陷。例如,一个实现缺陷可能是这样一种情况:当您无法连接到第一镜像时,您拥有冗余DB,但不尝试使用第二镜像。

对于第三点,重要的是记录异常并定期分析日志以查找任何奇怪的情况。所以,让我们开始具体回答。

首先

考虑“处理”异常。当您编写每个代码行时,请考虑可能阻止其完成的可能问题,并考虑可能的纠正操作(如果有可能)。错误消息不是好的处理方式,而是最后的策略。

不要开始编写try-catch(Exception),而应该选择特定的异常。如果您需要将字符串解析为数字等,则期望FormatException,如果您需要从Object转换为您的类型,则期望InvalidCastException

当您编写较低层次的图层时

不要犹豫地抛出异常!!不要像许多人一样做,例如返回null或使用(如ANSI C)布尔返回值和引用参数。异常就是为此而存在的。如果您可以处理异常(例如,您找不到本地文件,但知道您有远程备份,因此通过调用远程镜像来处理FileNotFoundException,但如果您仍然无法连接,则最终抛出异常),则这样做并尝试恢复计算,但如果您不能,则抛出异常。而且别忘了抛出内部异常,如果存在的话,因为它对于高层日志记录很有帮助。

基本上,即使您没有捕获任何异常,仍然可以决定自己抛出异常!这在函数参数无效时尤其推荐!

另一个好选择是仍然在底层记录。实际上,您想记录无论是否发生异常。

当您记录日志时

记得给消息适当的严重程度。如果你通过代码发现你的数据库离线了,那不是一个意外的异常。仍然将其记录为错误,但在调查日志时不要担心代码错误。相反,如果你捕获到你的代码无法识别的异常(例如NullReferenceException),则应该使用最高级别(即致命错误)进行记录,以赋予它最高优先级!

ASP.NET的良好策略

可以基于Page.OnError方法。如果你为站点的所有页面都有一个基础页面类,那么你应该绝对重写该方法。在该方法中,你应该首先记录你的异常。

你也不应滥用try-catch(Exception)块,因为如果你无法处理catch中的异常,你必须通过OnError来处理它。

当你运行这样的方法时,不要立即考虑Server.RemoveError()。你可以选择为HTTP 500错误设置静态HTML页面(当未处理的异常冒泡到ASP.NET运行时时触发),并向用户显示礼貌消息。

简而言之

  1. 如果发生任何奇怪的事情,请毫不犹豫地throw
  2. 按照你的建议,不要处理无法处理的异常(如果你捕获到一个无法处理的异常,请重新抛出它)
  3. 记录!!!!!!!!!!!!!!!!!
  4. 不要在公共网站上向最终用户披露异常详细信息,永远不要!!默认情况下,ASP.NET会防止这种情况发生,但你仍然可以使用OnError来打印堆栈跟踪
  5. 使用OnErrorApplication_Error作为单一中心点来处理所有意外异常
  6. 定期检查日志以查找代码问题,然后考虑维护/调试/修复它

抱歉djechelon,我之前没有及时回复你。我以为这会是一项比较简单的任务,但现在我无法集中精力处理异常和验证方面的问题。当然,我已经将您的回答标记为答案。在我详细研究项目的这一方面时,我会仔细阅读它,并希望在实施过程中有问题时您能够帮助我。但目前,如果您有任何文章或一些示例项目可以将您的观点转化为代码,那就太好了,谢谢!=) - Mazen Elkashef

1

如何/何时/在哪里捕获异常可能取决于你确切想要做什么,很难给出一个精确的通用答案。


关于您的具体问题,
我刚学了解了SqlException类,那个类是什么情况? 我曾经看到过一个处理SqlException再处理Exception的代码!
最好的做法是处理您认为可能发生的具体异常,如果您不确定此异常的类型,则可以使用“Exception”,如果您想要在“SQLException”上发生某些特定的事情,并希望在“Exception”上发生其他事情,则编写处理两者的代码当然没有任何问题。
“不要只是显式地捕获异常” 我认为这是指像这样的代码。
try 
{
   int i = 1/0;
} 
catch(Exception e)
{
  //do nothing
}

这个异常会被捕获,但你永远不会知道它发生了,因此这不是一个好主意,使用代码的人将会困惑不解。


如果我捕获了异常的抛出位置,那么我们可能已经有了一个处理它的计划,但是在我的数据库中应该捕获哪些信息以便了解任何人面临的问题呢?假设我会在所有层中使用 Exception,除了 DLL 我将使用 SqlException,因为我认为这将是此层中唯一可能发生的异常!+1 鉴于您的澄清。 - Mazen Elkashef

1

看看 elmah。它是用于 asp.net 的记录器。在一个漂亮的摘要页面上呈现所有错误。

http://code.google.com/p/elmah/

处理异常的最佳方式是在它们适用的特定层中处理。例如,如果是约束违规,比如有两个用户使用相同的名称,您应该让它冒泡到 UI 并向用户发出警报。
同样,任何业务规则违反都应该冒泡到 UI,以便最终用户知道出了什么问题。
SQL 连接错误最好在 DAL 中处理...等等。

业务规则的违反是否应该作为异常处理? - Paul Rowland
log4net记录到SQL Server也是一个不错的选择。使用L4N破折号进行报告。 - Mr Shoubs
Chris,我希望知道那些现成的第三方模块底层到底是如何实现的,这样我就可以为我的项目构建一个简单而有效的模块!你有什么想法或教程可以教我吗?另外,我应该从异常对象中收集哪些信息才能帮助我像亲眼目睹一样识别问题,以便我可以修复它! - Mazen Elkashef
顺便说一句,我同意Paul的观点。我认为它不应该这样! - Mazen Elkashef

1

我认为你在这里询问的是任何应用程序的错误/异常处理策略。

我认为它包括:

哪里 - 所有你认为可能会发生异常或需要更多监控的地方,例如数据库调用、外部服务调用、数组使用、用户输入解析、类型转换等等...

如何 - 所有高级别层都应该抛出异常,并且应该在入口点捕获并处理以了解根本原因。通常情况下,您可以在Application_Error()中执行此操作,在其中捕获异常并记录以进行故障排除。如何记录异常取决于您。基于您的要求和可用资源,日志文件或DB驱动日志是一个选项。


“并加工以了解根本原因。” - Mazen Elkashef
+1 顺便说一句.. 很好的回答,但我希望你能给我展示完整的情况,也许还有一些代码.. 不要给我初学者的例子!.. 我想看看它是如何真正实现的(特别是如何实现的部分!) - Mazen Elkashef

0

除了极为罕见的情况外,我只在涉及与服务和文件系统交互的 I/O 相关代码中使用异常处理,因为这些功能和维护超出了我的应用程序控制范围。

我一直认为使用 try/catch 语句来操纵程序中的逻辑(流程控制)与 if/else 语句的工作方式相同,是极其不良的做法。如果您正确使用手头的工具,大多数常见异常都可以避免。


抱歉罗布,我不太明白你在说if/else的事情,但当然我会努力进行验证并确保不会有任何错误出现在我的系统或代码中。但是,如果我的代码不完美,那该怎么办?当发现bug并引发错误时,我不希望我的系统终止或让访问者离开! - Mazen Elkashef
错误总是会出现 - 你打算怎么办 - 把整个应用程序都包裹在一个巨大的try/catch语句中吗?如果你对代码足够了解,知道需要一个try/catch语句,那么你也足够了解通过检查诸如空对象之类的事物来更优雅地处理错误。 - Rob
@iKashef,错误不等于异常。只有在没有其他选择时才使用try/catch是一个好的实践。例如,您不应该在用户输入时出现异常,而应该在异常发生之前对其进行验证。如果您的数据库硬盘已过期,并且有人正在尝试将某些内容保存到数据库中,则这是一个无法控制的异常,应该在您的DAL中捕获。 - Paul Rowland

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