如何将异常详细信息显示给用户以便在多层应用程序中进行解析

时间:2012-10-04 15:57:48

标签: c# entity-framework error-handling service-layer data-layer

我们的服务层中有以下代码,我们使用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之前,我们会进行某些客户端和服务器验证,但是我不确定如何处理未处理的异常。

例如,如果以某种方式c​​ontext.SaveChanges()抛出错误,我们如何将错误细节冒泡回到表示层?

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

    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 个答案:

答案 0 :(得分: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指定为知识类型。这样,这些故障将传达到客户端:

    [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/

答案 1 :(得分:1)

如果您打算使用它,您只需要在较低层中捕获异常。例如,您可能会捕获它,写入异常日志,然后重新抛出它。

至于返回值,我认为你不应该从多个地方返回。

相反,我认为这更好:

User user = null;

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

return user;

答案 2 :(得分:1)

  

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

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

如果你想向用户显示好消息(和/或在上层某处进行日志记录),请使用throw new ApplicationException("Failed to create user", ex);这样你可以得到好消息,并用堆栈跟踪冒出异常所以你可以在以后理解并解决问题。

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

祝你好运!

答案 3 :(得分:1)

您不需要在数据访问层中捕获异常,让它们自然地抛出。如果你需要对它进行业务流程,那么规则就是捕获异常。如果没有,那就让它成为。

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

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