Exception 如何在分层体系结构中处理异常?

Exception 如何在分层体系结构中处理异常?,exception,exception-handling,layer,n-tier-architecture,Exception,Exception Handling,Layer,N Tier Architecture,在你离开谷歌之前,我已经阅读了很多关于异常处理的文章、帖子和评论,但我仍然停留在这些特定的观点上 鉴于以下示例,您将如何处理以下场景 如果一个异常发生在DAL层中,并被包装在一个自定义异常中,以提供更多信息并更好地对其进行分类。如何记录它 如果我在DAL层中记录它,它将再次记录在全局处理程序中(使用elmah)。我可以让它传播,但如果ServiceLayer需要将该异常转换为用户更友好的消息,或者可能用于事务目的(想想回滚),会发生什么?我将丢失在DAL异常中收集的信息(无论如何,消息不一定是s

在你离开谷歌之前,我已经阅读了很多关于异常处理的文章、帖子和评论,但我仍然停留在这些特定的观点上

鉴于以下示例,您将如何处理以下场景

  • 如果一个异常发生在DAL层中,并被包装在一个自定义异常中,以提供更多信息并更好地对其进行分类。如何记录它 如果我在DAL层中记录它,它将再次记录在全局处理程序中(使用elmah)。我可以让它传播,但如果ServiceLayer需要将该异常转换为用户更友好的消息,或者可能用于事务目的(想想回滚),会发生什么?我将丢失在DAL异常中收集的信息(无论如何,消息不一定是stacktrace)


    就我个人而言,我更喜欢在采煤工作面(异常实际发生的地方)登录,因此在第一种情况下,我会登录DAL。如果我们不想传播错误,或者允许elmah记录错误,Bal(服务层)可以处理错误(这不是一件坏事,因为它会显示在错误页面上,并帮助跟踪异常)。 服务层还可以将DAL错误作为内部异常传递,以便在传播期间/之后可以访问它(如果需要),并且异常iteslf可以根据需要在层之间进行变异。用户通常不需要这些信息,只会收到通常的简化消息。
    也可以使用事件来收集异常数据(使用专门的事件参数)并只传回布尔方法返回,这可以更加可控和可定制-尽管这会让您有责任进行传播或不传播,并且它可能只用于“预期”的例外情况。

    就个人而言,我更喜欢在采煤工作面进行记录,因为实际发生了例外情况,所以在第一种情况下,我会在DAL中进行记录。如果我们不想传播错误,或者允许elmah记录错误,Bal(服务层)可以处理错误(这不是一件坏事,因为它会显示在错误页面上,并帮助跟踪异常)。 服务层还可以将DAL错误作为内部异常传递,以便在传播期间/之后可以访问它(如果需要),并且异常iteslf可以根据需要在层之间进行变异。用户通常不需要这些信息,只会收到通常的简化消息。
    也可以使用事件来收集异常数据(使用专门的事件参数)并只传回布尔方法返回,这可以更加可控和可定制-尽管这会让您有责任进行传播或不传播,并且它可能只用于“预期”的异常。

    专门记录DAL或任何层的问题是,我冒着多次记录同一异常的风险。假设我有一个非常通用的DAL方法,它可以从许多不同的服务中调用,在某些情况下服务层可以处理异常,而在其他情况下它不能,因此异常会传播到全局处理程序并记录两次。是的,但在这里需要权衡。如果您只是在DAl中捕获错误数据,并返回到服务层,其中包含异常数据,但没有异常(即在DAl中处理),那么在该异常被传递到下一行和该异常被中间问题隐藏之间可能会发生故障(这可能发生在内存异常的情况下,例如,内存异常可能导致无法处理的应用程序内错误)。这也是使用像elmah这样的通用错误报告系统的代价。您需要权衡在下游层中错误处理不当的可能性是否超过丢失因果异常的风险。另一个可能性是使用日志服务,并从您的层调用该服务,并在那里构建业务逻辑以决定他是否需要记录/重新记录或删除副本,然后就不用担心了。专门记录DAL或任何层的问题是,我会多次记录相同的异常。假设我有一个非常通用的DAL方法,可以从许多不同的服务中调用,在某些情况下,服务层可以处理异常,在其他情况下它不能,因此异常会传播到全局处理程序,并记录两次。是的,但在这里需要权衡。如果您只是在DAl中捕获错误数据,然后返回到服务层,并带有异常数据,但没有异常(即在DAl中处理)然后,在异常被传递到下一行和异常被中间问题隐藏之间可能会发生故障(例如,内存异常可能会导致无法处理的应用程序内错误)。这也是使用像elmah这样的通用错误报告系统的代价。您需要权衡在下游层中错误处理不当的可能性是否超过丢失因果异常的风险。另一个可能性是使用日志服务,并从您的层调用该服务,并在那里构建业务逻辑以决定他需要记录/重新记录或删除副本,然后就不用担心了。
     // UI
            public static GetUser(int userId)
            {
                // Should I do validation here or in service layer
                try
                {
                   IUserService s = new UserService(userId);
                   s.GetUser(userId);
                } 
                catch(ServiceLayerException ex)
                {
                    // ex.Message displayed to user
                }
    
            }
    
    
            // Service layer
            public User GetUser(int userId)
            {           
                try
                {
                    return repo.GetUser(userId);
                }
                catch(DALException ex)
                {
                    // user-friendly message displayed to user
                    throw new ServiceLayerException("User does not exist");
                }
            }
    
    
    
            // DAL
            public User GetUser(int userId)
            {
                try
                {
                    // Query for user, if fails throw DALException
                    return userId;
                }
                catch (SqlException ex)
                {
                    throw new DALException("Could not retrieve user with userId " + userId.ToString());
                }
    
            }