2

我们的服务层中有以下代码,我们使用 EF 将新用户添加到数据库中。

    public User AddUser(User user)
    {
        using (var context = DataObjectFactory.CreateContext())
        {
            var userEntity = Mapper.Map(user);

            context.AddObject("UserEntities", userEntity);

            context.SaveChanges();

            return Mapper.Map(userEntity);
        }         
    }

这由服务层通过以下方法调用:

    public UserResponse GetSubmitUser(UserRequest request)
    {
        var response = new UserResponse(request.RequestId);

        var user = Mapper.FromDataTransferObject(request.User);

        response.User = Mapper.ToDataTransferObject(UserDao.AddUser(user));

        return response;
    }

在到达 AddUser 之前,我们会进行某些客户端和服务器验证,但是我不确定如何处理未处理的异常。

例如,如果 context.SaveChanges() 以某种方式抛出错误,我们如何将错误详细信息返回到表示层?

我正在考虑将 try / catch 放在 AddUser 中,如下所示:

    public User AddUser(User user)
    {
        try
        {
            using (var context = DataObjectFactory.CreateContext())
            {
                var userEntity = Mapper.Map(user);

                context.AddObject("UserEntities", userEntity);

                context.SaveChanges();

                return Mapper.Map(userEntity);
            }  
        }
        catch (Exception)
        {
            return ??
        }      
    }

但是 AddUser 的返回类型是 User 并且我不确定发生异常时应该返回什么。如果我可以将异常详细信息返回给 UserResponse 方法,我可以在我们的响应对象中填充一些字段,这些字段用于保存错误详细信息,但现在确定从 catch 部分中返回什么。

我试图了解如何识别应该在多层应用程序中捕获和处理的异常,一个具有数据访问层、服务层、表示层等的异常。主要是想弄清楚如何向用户展示异常详细信息解析度。

谢谢

4

4 回答 4

2

我认为“BusinessExceptions”是您正在寻找的东西。

在 n 层应用程序中,从服务层获取或创建业务规则异常是很常见的。我猜您正在尝试使用您的示例验证一些业务规则,也许用户名是有效的,或者它在数据库中尚不存在。

对于这类问题,我总是使用 FaultExceptions 和自定义对象向客户端发送“可理解”的消息。这样我就可以区分系统异常、错误异常和业务规则异常(用户想知道的那些)。

这就是我通常的做法。我有一个 BusinessFault 对象,其中包含将由客户端处理并在必要时向用户显示的业务规则被破坏的数据:

[DataContract]
public class BusinessFault
{
    [DataMember]
    public BusinessFaultType Type { get; set; }

    [DataMember]
    public string Details { get; set; }

    [DataMember]
    public ErrorCode ErrorCode { get; set; }

    public BusinessFault(BusinessFaultType type, ErrorCode errorCode)
    {
        Type = type;
        ErrorCode = errorCode;
    }

    public BusinessFault(BusinessFaultType type, string details, ErrorCode errorCode)
        : this(type, errorCode)
    {
        Details = details;
    }

}

因此,每当我需要检查规则时,我都会像这样使用它(使用您的示例):

public void AddUser(User user)
{
if(!IsValidUser(user))
 throw new FaultException<BusinessFault>(new BusinessFault(BusinessFaultType.Validation, "Username",ErrorCode.AlreadyExists); 

using (var context = DataObjectFactory.CreateContext())
    {
        var userEntity = Mapper.Map(user);

        context.AddObject("UserEntities", userEntity);

        context.SaveChanges();

        return Mapper.Map(userEntity);
    } 
}

在我的服务合同中,我应该将我的 BusinessFault 指定为 knowntype。这样,这些故障将到达客户端:

    [OperationContract]
    [FaultContract(typeof(BusinessFault))]
    void AddUser(User user);                              

所以在客户端,我只需要一个针对 BusinessFault 的 try-catch:

try
{
    //WebService call
}
catch (FaultException<BusinessFault> ex)
{
var exception = ex.ToBusinessExeption();  //I use extensions Methods to convert it in a custom Exception with the parameters I sent. 
            throw exception;
}     

有一篇非常好的文章:http ://www.c-sharpcorner.com/UploadFile/afenster/wcf-error-handling-and-faultexceptions/

于 2012-10-04T16:20:30.823 回答
1

如果你打算对它做点什么,你只需要在你的低层捕获异常。例如,您可能会捕获它,写入异常日志,然后重新抛出它。

至于返回值,在我看来,你不应该从多个地方返回。

相反,我认为这更好:

User user = null;

try
{
   //Try to set up user
}
catch(Exception ex)
{
   //Log exception
   throw;
}

return user;
于 2012-10-04T16:02:54.547 回答
1

但是 AddUser 的返回类型是 User 并且我不确定发生异常时应该返回什么

这取决于 - 通常,您不想返回值,但您将记录异常然后调用throw;(或者您将抛出您自己的异常,该异常是包装原始异常,您的选择)并将异常冒泡,直到你会在某个地方捕捉到它,向用户显示好消息,然后记录它。

如果您想向用户显示好消息(和/或在上层某处进行日志记录),使用throw new ApplicationException("Failed to create user", ex);这种方式您可以获得好消息,并使用堆栈跟踪冒泡异常,以便您稍后理解并修复问题.

在某些情况下,您可以返回 null 并只记录异常。通常,当你不想冒泡异常时,如果它不是关键的,你不想因为它退出当前代码路径,你就会这样做。

祝你好运!

于 2012-10-04T16:03:38.197 回答
1

您不需要在数据访问层捕获异常,让它们自然抛出。规则是,如果您需要对其进行业务处理,您只需捕获异常。如果没有,那就顺其自然吧。

因此,所有异常都将捕获到应用程序的顶层,以便记录故障排除。

如果您的应用程序是 Web,您可以使用一些支持日志处理程序(如Elmah )的日志库来拦截请求级别。

于 2012-10-04T16:06:02.150 回答