2013-01-14 98 views
1

我是OOP的新手,所以我需要幫助來了解這是否是正確的方式來處理它。 我有一個3層Web項目(+ DTOs),我試圖理解這是從業務對象返回到演示層的「錯誤」的最佳方式。 特別是現在我正面臨着創建一個用戶。假設我想在網站註冊時在db中創建用戶,並且我需要告訴實際用戶用戶名或電子郵件是否已被使用(這僅僅是一個示例)。例如,ASP.NET Membership.CreateUser()方法傳遞一個MembershipCreateStatus對象byRef,因此該方法用於返回一個枚舉(它駐留在另一個命名空間中...)以傳遞嘗試的狀態,並且這個可能是DuplicateEmail,DuplicateUserName等等。來自業務層的ASP.NET自定義異常處理

我實施了另一種基於例外的方式,但我希望您對此有所意見。在創建用戶BLL管理器類我創建了一個嵌套的錯誤時拋出類和嵌套枚舉的錯誤類型是這樣的:

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和人造人好心建議(我標誌着他的回答只是因爲它是更完整的布萊恩也許其它感興趣的網友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

(這個回答只是爲@BrianMains的建議提供了使用返回代碼而不是例外的建議,相關文檔太大而不適合評論。)

從上異常MSDN文檔:當你拋出或處理異常

系統資源和執行時間的顯著量使用。拋出異常只是爲了處理真正的特殊情況,而不是處理可預見的事件或流量控制。例如,如果方法參數無效,則您的應用程序可以合理地拋出異常,因爲您期望使用有效參數調用您的方法。無效的方法參數意味着發生了非同尋常的事情相反,如果用戶輸入無效,不會拋出異常,因爲您可能希望用戶偶爾輸入無效數據。在這種情況下,請提供重試機制,以便用戶輸入有效的輸入。

僅在異常情況下拋出異常,然後在適用於大多數應用程序的通用異常處理程序中捕獲異常,而不是適用於特定異常的處理程序。這種方法的基本原理是,大多數錯誤可以通過錯誤附近的驗證和錯誤處理代碼來處理;不需要拋出或捕捉異常。通用異常處理程序捕獲應用程序中任何位置引發的真正意想不到的異常。

另外,當返回碼足夠時不會拋出異常;不要將返回代碼轉換爲異常;並且不經常捕獲異常,忽略它,然後繼續處理。

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

(高亮礦)

+0

謝謝大家。我沿着「自定義例外」的路徑走,因爲我在某處讀到完全相反的東西。我讀過基於組件的場景(我猜想多層架構堅持),組件不應該返回「幻數」或代碼,而是返回異常。但我想,因爲每次都必須實例化自定義異常並檢查自定義枚舉,所以這與處理自定義返回代碼非常相似,只是更昂貴。 – Manight

+0

我認爲你讀的是在發生異常情況時,函數不應該返回「幻數」。例如,一個函數在成功時返回0,在那裏失敗時返回-1,這在.NET中是不受歡迎的。在這種情況下,優先考慮例外。但是,如果函數是*做*某事,並且結果可能是一些*預期的事情,那麼返回代碼是適當的。 – JDB

2

對於這一點,我會按照會員API做什麼。從您的業務組件返回枚舉,視圖可以使用該枚舉來檢查響應。所以你返回一個像你提到ASP.NET頁面那樣的值的枚舉,然後檢查那裏的類型。你可以做你正在做的事情,但從我看到的我不認爲這是必要的;另外,拋出異常很昂貴。

爲了闡明我的意思是枚舉是從業務組件的調用者返回它,而不是通過例外。

+1

1返回碼將是在這種情況下合適的。在某些情況下,您可能想要返回許多值(數據集,以及狀態碼等),您可以返回使用適當值初始化的更復雜的「CreateLoginResult」對象。 – JDB

+0

同意。在這裏似乎沒有必要,但我遇到了這種情況。 –