业务层的ASP.NET自定义异常处理

时间:2013-01-14 20:01:09

标签: asp.net exception exception-handling nested-class n-layer

我是OOP的新手所以我需要帮助才能理解这是否是处理它的正确方法。 我有一个3层Web项目(+ DTO),我试图理解这是将Business Objects返回到表示层的“错误”的最佳方法。 特别是现在我正面临这个创建用户。假设我想在网站注册时在数据库中创建用户,我需要告诉实际用户是否已经使用了用户名或电子邮件(这只是一个例子)。

例如,ASP.NET Membership.CreateUser()方法传递一个MembershipCreateStatus对象byRef,因此该方法用于返回一个枚举(位于另一个命名空间...)以传递尝试的状态,这可能是DuplicateEmail,DuplicateUserName等。

我基于异常实现了另一种方式,但我希望你对此有所了解。在创建用户的BLL管理器类中,我以这种方式创建了一个嵌套的Excpetion类和嵌套的错误类型的枚举:

Public Class UserManager
    Public Enum ErrorType
        DatabaseError = 1
        UserExists = 2
        EmailExists = 3
    End Enum

    Public Class ManagerException
        Inherits Exception

        Public Property ErrorType As ErrorType
        Public Property SuggestedUserName As String
        Public Property SuggestedEmail As String

        Public Sub New()
            MyBase.New()
        End Sub

        Public Sub New(message As String)
            MyBase.New(message)
        End Sub

        Public Sub New(message As String, inner As Exception)
            MyBase.New(message, inner)
        End Sub
    End Class


    Public Function CreateUserLogin(user As EvaVwUserLogin) As Guid
        If user Is Nothing Then
            Throw New ApplicationException("No user suppied")
        End If

        If String.IsNullOrWhiteSpace(user.Password) OrElse String.IsNullOrWhiteSpace(user.UserName) Then
            Throw New ApplicationException("Password or username missing")
        End If

        If CheckDuplicateUserName() Then
            Dim ex As New ManagerException("Username exists")

            ex.ErrorType = ErrorType.UserExists
            ex.SuggestedUserName = "this username is free"

            Throw ex
        End If
    End Function
End Class

然后在UI层(后面的aspx代码)中,我调用管理器并检查异常,如下所示:

        Dim userManager As New UserManager

        Try
            userManager.CreateUserLogin("test", "test")
        Catch ex As UserManager.ManagerException
            If ex.ErrorType = userManager.ErrorType.UserExists Then
                Dim suggestedUsername = ex.SuggestedUserName

                ' Display error message and suggested user name
            End If
        End Try

这是一个正确的方法,考虑到异常和枚举都非常特定于这个管理器,所以如果我沿着这条路线走下去,每个管理器都会有它的嵌套ManagerException和相关的枚举吗?

提前感谢您的意见。


跟进Brian和Cyborg友好建议的“自定义代码”场景(我标记他的答案只是因为它更完整Brian也许其他用户对MS建议感兴趣)你认为嵌套自定义返回对象和相关枚举吗?经理班是个好主意? 由于这些枚举将与此经理类严格相关(并且BLL中的每个managar类都有自己的),您认为我仍然可以使用它们作为状态代码传递吗?

编辑:我这样重构了......你认为没关系吗?

Public Class UserManager
    Public Enum ErrorType
        DatabaseError = 1
        UserExists = 2
        EmailExists = 3
    End Enum

    Public Class ErrorData
        Public Property ErrorType As ErrorType
        Public Property SuggestedUserName As String
        Public Property SuggestedEmail As String
    End Class

    Public Function CreateUserLogin(username As String, password As String, ByRef errorData As ErrorData) As Guid
        Dim user As New EvaVwUserLogin

        user.UserName = username
        user.Password = password

        Return CreateUserLogin(user, errorData)
    End Function

    Public Function CreateUserLogin(user As EvaVwUserLogin, ByRef errorData As ErrorData) As Guid
        If user Is Nothing Then
            Throw New ApplicationException("No user object")
        End If

        If String.IsNullOrWhiteSpace(user.Password) OrElse String.IsNullOrWhiteSpace(user.UserName) Then
            Throw New ApplicationException("Missing password or username")
        End If

        Dim hashedPassword As String

        hashedPassword = Crypto.HashPassword(user.Password)

        If UserExists(user) Then
            errorData.ErrorType = ErrorType.UserExists
            errorData.SuggestedUserName = "this username is free"
            Return Nothing
        End If
        .....
    End Function
End Class

在表达层:

        Dim userManager As New UserManager
        Dim managerError As New UserManager.ErrorData
        Dim userId As Guid

        userId = userManager.CreateUserLogin("test", "test", managerError)

        If userId = Nothing Then
            If managerError.ErrorType = userManager.ErrorType.UserExists Then
                Dim suggestedUserName = managerError.SuggestedUserName

                ' Do something with suggested user name
            End If
        End If

2 个答案:

答案 0 :(得分:2)

为此,我会遵循Membership API的功能。从业务组件返回枚举,视图可用于检查响应。因此,您返回一个枚举,其中包含您向ASP.NET页面提及的值,并检查其中的类型。你可以做你正在做的事情,但从我看到的我不认为这是必要的;另外,抛出异常是很昂贵的。

澄清我的意思是enum是从业务组件的调用者返回它,而不是通过异常。

答案 1 :(得分:2)

(这个答案只是为@BrianMains建议使用返回代码而不是异常提供支持。相关文档太大而无法用于评论。)

关于例外的MSDN文档:

  

抛出或处理异常时会使用大量系统资源和执行时间。抛出异常只是为了处理真正特殊的条件,而不是处理可预测的事件或流量控制。例如,如果方法参数无效,您的应用程序可以合理地抛出异常,因为您希望使用有效参数调用方法。无效的方法参数意味着发生了特殊的事情。相反,如果用户输入无效不会抛出异常,因为您可能希望用户偶尔输入无效数据。在这种情况下,请提供重试机制,以便用户输入有效的输入。

     

仅针对特殊情况抛出异常,然后捕获适用于大多数应用程序的通用异常处理程序中的异常,而不是适用于特定异常的处理程序。这种方法的基本原理是大多数错误都可以通过验证和错误处理代码来处理错误;没有异常需要抛出或抓住。通用异常处理程序捕获应用程序中任何位置引发的真正意外异常。

     

此外,在返回代码足够时不抛出异常;不要将返回代码转换为异常;并且不要经常捕获异常,忽略它,然后继续处理。

http://msdn.microsoft.com/en-us/library/system.exception.aspx

(突出我的)