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之前,但我不知道如何處理未處理的異常(S)。

例如,如果以某種方式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的返回類型是用戶,我不知道我應該是當發生異常返回什麼。如果我可以將異常詳細信息返回給UserResponse方法,則可以在響應對象中填充某些字段,這些字段用於保存錯誤詳細信息,但現在確定要從catch部分返回什麼內容。

我想了解如何識別應該在多層應用程序中捕獲和處理的異常,例如數據訪問層,服務層,表示層等。主要試圖找出如何表達異常詳細信息給用戶解決。

感謝

回答

2

我認爲「BusinessExceptions」是你正在尋找的東西。

在n層應用程序中,從服務層獲取或創建業務規則異常時很常見。 我想你正試圖用你的例子來驗證一些業務規則,也許這個用戶名是有效的或者它不存在於數據庫中。

對於這類問題,我總是使用FaultExceptions和自定義對象向客戶端發送一條「可以理解」的消息。這樣我就可以區分系統異常,錯誤異常和業務規則異常(用戶想知道的異常)。

這是我通常這樣做的。我有一個包含將由客戶在必要時procesed並顯示,業務規則破碎的數據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);        

所以在客戶端我需要的是一個try-catch特定的BusinessFault:

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/

+0

感謝您的詳細解釋。 – 03Usr

1

你只需要捕獲異常在較低層,如果你打算用它做什麼。例如,您可能會捕獲它,寫入例外日誌,然後重新拋出它。

至於返回值,在我看來,你不應該從多個地方返回。

相反,我認爲這是更好的:

User user = null; 

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

return user; 
1

但ADDUSER的返回類型是用戶,我不知道我 應該是當發生異常

返回什麼

這取決於 - 通常,你不想返回值,但你會記錄異常,然後打電話throw;(或者你會拋出你自己的例外that'a包裝orig inal exception,您的選擇),並將異常情況向上冒泡,直到某處您能夠捕捉到它,向用戶顯示好消息並記錄下來。

如果你想向用戶展示漂亮的消息(和/或在上層進行日誌記錄),使用throw new ApplicationException("Failed to create user", ex);這樣你可以得到很好的消息,並用堆棧跟蹤冒出異常,這樣你就可以理解並在稍後解決問題。

在某些情況下,您可以返回null並僅記錄異常。通常情況下,當您不想冒出異常,如果它不重要,並且不希望因此而退出當前代碼路徑時,可以這樣做。

祝你好運!

1

你不需要在Data Access Layer中捕獲異常,讓它們自然拋出。如果您需要在其上執行業務流程,您只需捕捉異常即可。如果沒有,就讓它成爲。

因此,所有的例外都會出現在應用程序的頂層,以便記錄故障排除。

如果您的應用程序是web,您可以使用一些支持日誌處理程序(如Elmah)的日誌庫在請求級別攔截。

相關問題