在BLL,DAL或PL中,我应该在哪里处理异常?

时间:2010-06-14 17:03:19

标签: c# .net architecture layered

哪个是处理异常的最佳位置? BLL,DAL还是PL?

我是否应该允许DAL和BLL中的方法将异常抛出链并让PL处理它们?或者我应该在BLL处理它们?

e.g

如果我的DAL中有一个方法发出“ExecuteNonQuery”并更新了一些记录,并且由于一个或多个原因,0行会受到影响。现在,我应该如何让我的PL知道是否发生了异常,或者确实没有与该条件匹配的行。我应该在我的PL代码中使用“try catch”并通过异常让它知道,或者我应该在DAL处理异常并返回一些特殊代码,如(-1)让PL区分(异常)和(不)行匹配条件即受影响的零行)?

7 个答案:

答案 0 :(得分:4)

将DAL冒泡中引发的异常放到PL中是没有意义的 - 如果无法建立数据库连接,用户应该如何做出反应?

尽早赶上并处理异常,如果您可以处理它们。不要只是吞下它们而不输出提示或日志消息 - 这将导致严重的困难和难以跟踪的错误。

答案 1 :(得分:3)

这是一个很大的话题,有很多不必要的争议(声音很大的人给出了不好的信息!)如果你愿意处理这个问题,请遵循s1mm0t的建议,这大多是令人满意的。

但是,如果你想要一个单词的答案,将它们放在PL中。严重。如果你可以逃脱它将你的错误处理放在一个全局异常处理程序中(所有错误都应该记录并提供代码以出于安全原因查找生产中的日志(尤其是web),但在开发过程中提供完整的详细信息速度原因)。

编辑:(澄清) 你必须处理一些错误 - 但这不是'每个功能'的规范。大部分时间让它们冒泡到PL并使用您自己的代码处理.NET的全局错误:通过一个可通过事件处理程序从所有3个层访问的公共例程从那里记录完整的调用堆栈(请参阅消息底部的EDIT) )。这意味着您将通过所有代码尝试/捕获;只是您期望和错误的部分,并且可以在那里处理它,或者非关键部分,您可以使用它来记录错误并告知用户不可用的功能(这对于超级可靠/关键程序来说更为罕见)

除此之外,在使用有限资源的项目时,我经常使用'using'关键字或try / finally / end尝试没有catch。用于多线程锁/互斥/重新进入防止标志/等。你还需要在所有情况下尝试/最终,所以你的程序仍然有效(特别是有状态的应用程序)。

如果你不正确地使用例外(例如,当你应该使用IF语句来处理非bug时或者在你尝试之前检查它是否有效),这种理念会更加分散。

旁注,在胖客户端应用程序中,特别是当有可能丢失大量数据或用户输入时,您可能会更好地尝试保存数据的更多尝试/捕获(标记为尚未 - 当然有效。)

编辑:至少需要在PL 中使用日志记录例程 - 这将根据平台的不同而有所不同。我们正在开发的应用程序与3 PL版本共享BLL / DAL:ASP.Net版本,winforms版本和控制台应用程序批处理模式回归测试版本。被调用的日志记录例程实际上在BLL中(DAL仅抛出错误或完全处理它获取或重新抛出它们)。然而,这引发了由PL处理的事件;在Web上,它将它放在服务器的日志中,并显示Web样式的错误消息(生成的友好消息);在WinForms中会出现一个特殊的消息窗口,其中包含技术支持信息等,并在幕后记录错误(开发人员可以做一些'秘密'来查看完整信息)。当然,在测试版中,它是一个更简单的过程,但也有所不同 不知道我是如何在BLL中完成的,除了传递参数'what platform',但由于它不包括日志所依赖的winforms或asp库,这仍然是一个技巧。

答案 2 :(得分:2)

简短的答案取决于它!

如果您可以使用它做一些有用的事情,那么您应该只处理异常。 “有用的东西”又取决于你在做什么。您可能希望记录异常的详细信息,虽然这不是真正处理它,并且您应该在大多数情况下登录后重新抛出异常。您可能希望将异常包装在其他(可能是自定义的)异常中,以便向异常添加更多信息。当@mbeckish触及时,你可能想尝试通过重试操作来恢复异常 - 但是你应该注意不要永远重试。最后(请原谅)您可能希望使用finally块来清理任何资源,例如开放式数据库连接。您选择对异常做什么会影响您处理它的位置。除了向用户报告发生了错误之外,很可能没有很多有用的事情可以用来处理,在这种情况下,在UI层处理异常是可以接受的。并向用户报告问题(您可能应该记录异常,进一步向下)。

当你自己抛出异常时,你应该只在“异常”的情况下抛出异常,因为抛出异常会有很大的开销。在您的示例中,如果您的操作没有更新记录,您建议您可能会考虑抛出异常。这真的很特别吗?在这种情况下更好的做法是返回更新的记录数 - 这可能仍然是需要向用户报告的错误情况,但是由于与DB的连接失败,因此命令失败也不例外走了。

This是关于异常处理最佳做法的合理文章。

答案 3 :(得分:1)

知道如何正确设置的层应该是处理异常的层。 例如,如果您决定通过重试查询一定次数来处理死锁错误,那么您可以将其构建到DAL中。如果它继续失败,那么您可能希望让异常冒泡到下一层,然后可以决定它是否知道如何正确处理此异常。

答案 4 :(得分:0)

应用程序中的所有图层都应该优雅地管理异常。这被称为横切corncern,因为它出现在所有层中。 我相信使用像Enterprise Exception Block这样的统一框架,你最终会得到一个更好的代码。 看一下这篇文章

http://msdn.microsoft.com/en-us/library/ff664698(v=PandP.50).aspx

掌握它需要一些时间,但那里有很多例子和截屏。

答案 5 :(得分:0)

如何处理异常取决于技术和业务需求。对于复杂或非常重要的数据库更新,我包括将一小段已知错误备份传递给DL的params。这样,在某些情况下可以以编程方式解决已知的错误场景。在其他情况下,需要记录错误,并且应该通知用户错误。

我做了一个通知人类有错误的做法。记录,日志记录将为我们提供详细信息,但它不能替代人类的响应时间。不仅如此,还有为什么要强迫开发人员观看系统日志,看看事情是否正在向南?谈论不必要的费用。

如果您有时间定义潜在的错误/异常并以编程方式解决它们,那么请务必这样做。很多时候错误/异常是意外的。这就是为什么重要的是为那个意想不到的事情做好准备,以及比涉及到一个人更好的方法。

总的来说,在规划异常处理时,应该处于守势。程序增长或死亡。增长的一部分是引入错误。因此,不要旋转你的车轮试图杀死它们。

答案 6 :(得分:-2)

问题是你的例外情况在哪里?如果它是数据访问异常,则应该在DAL中捕获。如果是逻辑异常,则应该在BLL中捕获。如果是演示文稿例外,那么在PL。

例如,如果您的DAL抛出异常,它应该返回null或false或者BLL的任何情况。如果DAL返回null,你的BLL应该知道该做什么,也许它会直接通过它,也许它会尝试调用另一个函数,等等。如果BLL从DAL传递一个null或者返回一些特定的东西,你的PL也是如此。然后,表示层应该能够通知最终用户存在问题。

当然,您不会收到详细的异常消息,但就您的用户而言,这是一件好事。您应该有一个灵活的日志记录系统来捕获这些异常,并将它们报告给数据库或ip:port或您决定的任何内容。

基本上你需要考虑separation of concerns如果问题是数据问题或逻辑问题,应该相应地处理。