2009-12-11 46 views
3

我有一个三层结构
1.介绍层
2.业务层
3.数据层
表示层通过服务门面业务层交互。现在我很困惑我应该在哪里抛出异常,我应该在哪里登录它们,我应该在哪里捕捉并吞下它们。目前,我正在登录后在表示层中吞噬异常,而我正在记录并将它们扔到其他地方。这会导致异常获得记录三次。这不是一个大问题,但我想知道关于这方面的最佳做法。何时抛出异常以及何时记录它们?

例如: 表示层代码:

try 
{ 
    UserService.GetAllUsers() ; 
} 
catch(Exception ex) 
{ 
    Logger.log(ex) // exception gets logged here 
    // redirect to a friendly user error page 
} 

UserService层代码

try 
{ 
    IUserDAO userDAO = ServiceRegistry.GetRegistry().GetDAOFactory().GetUserDAO() ; 
    return userDao.GetAllUsers() ; 
} 
catch (Exception ex) 
{ 
    Logger.log(ex) ; // and here ! 
    throw; 
} 

DAOLayer代码

try 
{ 
    // All db interaction code 
} 
catch(Exception ex) 
{ 
    Logger.log(ex) //and here !! 
    throw ; 
} 
+0

这一切都在同一台物理机器上?或者你有服务器和客户端?在我们的应用程序中,我们通常(尝试记录)所有物理机器上的错误消息...... – Fortega 2009-12-11 07:18:04

+1

当前这些都在同一台物理机器上,但将来我们可能会将它们放在不同的物理机器上。应该这样吗? – 2009-12-11 07:21:10

+0

我认为它的确如此。如果服务器上存在异常,那么您希望将其记录在那里,但也要在客户端调用导致异常发生的方法,以便在两个位置上都可以追踪错误。 它可能看起来像你记录了太多/太多,但由于它会导致性能或存储问题的机会非常小,所以我会像这样离开它... – Fortega 2009-12-11 07:26:16

回答

4

绝对没有必要将每段代码放在try-catch块中。例如,如果您的'DAOLayer'中发生异常,则您的日志文件将包含3次相同的异常...

请记住黄金法则有例外 - 例外应该是例外!这通常意味着您应该只捕获您能够处理的异常 - 您应该忽略的所有其他异常 - 较高级别的处理程序应该处理这些异常。

如果担心未处理的异常会导致应用程序崩溃(并且正确如此),则应该查看.Net公开的用于处理未处理的异常的两个事件。第一个是AppDomain.CurrentDomain.UnhandledException,第二个是Application.ThreadException(它位于Windows.Forms命名空间中)。

1

我实在看不出为什么你的日志记录例外并重新推出它。当然无论哪个进程最终吞下它都可以进行日志记录。如果您想记录该信息,则可以简单地使用ex.StackTrace来获取调用堆栈。

一般情况下,重新抛出异常时导致异常的问题,是不是可以在代码是在一级处理,你会做什么。您通常会使用更具体的catch块来捕获这些块并进行适当的响应(例如,如果由于网络超时而发生异常,您可以重试连接或尝试连接到备份服务器)。您需要在修复它的地方记录异常并继续。

如果在得到异常的地方没有什么可以做的,那么如果我不能指望进一步调用堆栈中的某些东西来为我管理日志记录,我只会费心去捕获并记录它。否则,它只会创建一个相当无意义的重复消息。

+0

图层的客户端可能会改变,如果我没有登录我的图层,我有点依赖客户端来做日志记录,如果他们不这样做,我就会喝汤。 – 2009-12-11 07:43:50

+1

那么,这是一个明智的理由登录多个地方 - 因为你不能指望客户端照顾日志记录。可解决的错误仍然应该单独被捕获。 – 2009-12-11 08:19:04

1

你应该抛出异常时,特殊的事情发生了 - 任何层上......如果你期待一些错误条件上来定期,代码为他们 - 显示错误,给用户和手段来修复错误。

记录下所有的警示,无一例外!很高兴有这些数据,如果你按照我以前的建议,你不会有太多的。

你应该从未吞例外。往上看。你会如何知道事情是否出错?

+0

吞并异常而不是允许应用程序失败有时可能是正确的调用。它正在交易鲁棒性的正确性,有时鲁棒性更重要。 – 2009-12-11 07:27:51

+0

始终记录。您可以根据要求决定是否要引发异常。 – Oded 2009-12-11 08:48:22

1

我倾向于做的是为每个级别一个例外,我包装异常,并通过它,如果向上的下一层无法处理异常。

例如,如果您尝试更新数据库,但主数据库已关闭,则可能只需转到辅助数据库,以便尝试该操作,如果它工作,则记录日志但不通过它在。

我倾向于通过对不能处理的异常,直到我到达顶层。在那里,对于某些错误将它们传递给客户端,如果它是用户可以做某些事情的例外情况,则以其他方式记录并吞下。

如果它类似于内存不足,那么在应用程序崩溃之前让用户知道,并准备妥善地死去。

0

而不是在自定义异常中包装异常或仅依靠StackTrace为您提供在最高级别登录异常时需要的所有信息,您可以使用ex.Data在传递异常之前添加有关该异常的更多信息链,例如ex.Data.Add("filename", filename)。您的日志代码可以转储出所有这些附加属性。这可能会为您提供足够的信息来了解抛出异常的原因并重现它。