何时抛出异常以及何时记录它们?

时间:2009-12-11 07:10:03

标签: .net exception-handling

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

例如: 表示层代码:

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

用户服务层代码

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 ;
}

5 个答案:

答案 0 :(得分:4)

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

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

如果您担心未处理的异常会使您的应用程序崩溃(并且理所当然),您应该查看.Net公开的2个事件来处理未处理的异常。第一个是AppDomain.CurrentDomain.UnhandledException,秒是Application.ThreadException(在Windows.Forms命名空间中)。

答案 1 :(得分:1)

我真的不明白为什么你要记录异常并重新抛出它。当然无论哪个过程最终吞下它都可以进行日志记录。如果要记录该信息,可以使用ex.StackTrace来获取调用堆栈。

通常,重新抛出异常就是当导致异常的问题不能在代码所处的级别解决的问题时。您通常使用更具体的catch块来捕获这些并适当地响应(例如,如果由于网络超时而导致异常,则可以重试连接或尝试连接到备份服务器)。您需要在修复它的位置记录异常,然后继续。

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

答案 2 :(得分:1)

当特殊情况发生时,您应该抛出异常 - 在任何层上......如果您希望定期出现一些错误条件,为它们编写代码 - 向用户显示错误并修复错误。< / p>

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

你应该从不吞下异常。往上看。如果出现问题,您怎么知道呢?

答案 3 :(得分:1)

我倾向于为每个级别创建一个异常,如果下一层不能处理异常,我会将异常包装并传递给它。

例如,如果您尝试更新数据库,但主数据库已关闭,您可能只需要转到辅助数据库,因此您可以尝试使用它,如果它可以正常运行,则会记录,但不要通过它上。

我倾向于传递无法处理的异常,直到我到达顶层。在那里,因为一些错误将它们传递给客户端,如果它是一个例外,用户可以做一些事情,但否则,记录和吞下。

如果内存不足,那么在应用程序崩溃之前让用户知道并准备优雅地死掉。

答案 4 :(得分:0)

不是将异常包装在自定义异常中,也不仅仅依靠StackTrace为您提供在最顶层记录异常时所需的所有信息,而是可以使用ex.Data添加有关异常的更多信息。把它传递给链子,例如ex.Data.Add("filename", filename)。然后,您的日志记录代码可以转储所有这些附加属性。这可能会为您提供足够的信息来理解抛出异常的原因并重现它。