2

我得到了一個帶有控制器和服務的API,當調用控制器中的一個動作時,我必須應用一個驗證,此驗證需要檢查數據庫中的數據以驗證它是否正確。在webapi中的異常處理MVC.net

據我所看到的也有叫「更新」,以防止錯誤

public IActionResult UpdateCustomer(CustomerDto customer) 
{ 
    if (!customerService.Validate(customer)) 
    { 
     return Send400BadRequest(); 
    } 
    customerService.Update(customer); 

    return Send200Ok(); 
} 

2-呼叫內更新驗證和罰球前處理這個

1-驗證兩種方法例外。

public IActionResult UpdateCustomer(CustomerDto customer) 
{ 
    customerService.Update(customer);  
    return Send200Ok(); 
} 

在客戶服務

public void Update(CustomerDto customer) 
    { 
    if (!Validate(customer) 
     throws new CustomValidationException("Customer is not valid"); 
    //Apply update 
    } 

我們已經有一個ActionFilter處理CustomValidationException所以它會返回一個錯誤請求。

1) 優點 +不要使用例外爲使用運行流動

缺點 -Controller是更多的脂肪,對每一種情況下,將決定哪個是輸出

2多個決策) 優點 +操作更原子化,所有邏輯都在服務內部。 +更容易測試 +該方法的每次使用都將被驗證。

缺點 - 使用異常來管理流程。

哪一個更好的解決方案?

我確實需要論據來捍衛其中的一個。

+1

我不會考慮2個額外的代碼行膨脹控制器IMO。 –

+0

對我來說不是那麼臃腫與否,但更多的是決定不應該在控制器中 – Balder

+1

@Balder,使用另一個動作過濾器在進行動作之前進行驗證。貫穿始終的關切和單一責任原則。 – Nkosi

回答

0

我寧願2 :)

因爲我覺得服務可以從另一個節點不僅asp.net控制器如果所有的驗證邏輯是一樣的服務單層處理,被稱爲所以這將是對我好層。

0

我認爲通過使用httpresponse消息來處理異常比其他任何人都好得多。至少你得到了正確的錯誤響應,輸出正確的http響應消息。

 public HttpResponseMessage TestException() 
     { 
     try 
     { 
      //if your code works well 
      return Request.CreateResponse(HttpStatusCode.OK); 
     } 
     catch (Exception ex) 
     { 

      return Request.CreateErrorResponse(HttpStatusCode.ExpectationFailed, ex.ToString()); 
     } 
     } 
0

我會做這種方式:

public IActionResult UpdateCustomer(CustomerDto customer) 
    { 
    try 
     { 
     consumerService.Update (customer); 
     } 
    catch (CustomValidationException) 
     { 
     return Send400BadRequest(); 
     } 

    return Send200Ok(); 
    } 

而在你的CustomerService:

public void Update(CustomerDto customer)  
     { 
     if (!Validate(customer)) 
      throw new CustomValidationException("Customer is not valid"); 
     } 

這樣,你的服務有驗證邏輯。因此,任何其他您的服務的調用者在嘗試更新之前也將驗證其輸入,因此會得到適當的錯誤消息。 您的控制器將不會有任何驗證碼。此外,擁有try-catch塊意味着你可以優雅地處理更新調用可能拋出的任何其他錯誤。希望有所幫助。

1

我反對在這裏的其他意見,並說第一種方法都清楚地說明了你的方法的意圖是什麼,如果你決定不返回400錯誤,它有點容易把它拉下來場景#1。

此外,對異常的一些想法。異常應該是例外,這意味着代碼中出現意外事件。沒有通過驗證檢查的公司不是異常事件,它可以通過或不通過。將用戶對象傳入ValidateCompany()方法應該會引發異常。

Here是異常拋出類似主題上的一個很好的答案。它使用一個簡單的示例問題來確定何時應該引發異常。

關於「更容易測試」 - 我看不出如何。您的控制器將進行兩項測試,包括您選擇的任何選項,有效的公司和無效的公司。您的服務將通過您選擇的任何選項,有效的公司和無效的公司進行兩項測試(顯然簡化了您的服務層)。在任何情況下,您都希望確保您的控制器操作和您的服務層可以處理無效且有效的公司對象。

0

接收一個客戶可驗證模型,通過該模型的數據服務層,並且在所述控制器執行異常處理 如果數據服務層失敗。

客戶模式

實施IValidatableObject捕獲業務邏輯相關的錯誤。

public class CustomerModel : IValidatableObject 
{ 
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
    { 
     // example validation 
     if (Balance < 100) 
      yield return new ValidationResult("Balance >= 100 req.", new [] { nameof(Balance) }); 
    } 
    public string Name { get; set; } 
    public double Balance { get; set; } 
} 

API控制器

在面向公衆的UpdateCustomer API方法接收一個CustomerModel,然後引用ModelState,以確定客戶是否有效。

public IActionResult UpdateCustomer(CustomerModel customer) 
{ 
    if(ModelState.IsValid) // model validation succeeded 
    { 
     try 
     { 
      customerService.Update(customer); 
     } 
     catch (ServiceUpdateException svcEx) 
     { 
      // handled failure at the service layer 
      return Conflict(); 
     } 
     catch (Exception ex) 
     { 
      // unhandled error occured 
      return InternalServerError(ex); 
     } 
     // update succeeded 
     return Ok(); 
    } 
    // invalid model state 
    return BadRequest(); 
} 

服務(數據層)

public void Update(Customer customer) 
{ 
    //Apply update 
    try 
    { 
     database.Update(customer); 
    } 
    catch (DataStorageException dbEx) 
    { 
     throw new ServiceUpdateException(dbEx); 
    } 
    catch 
    { 
     throw;//unknown exception 
    } 
} 
3

如果你有業務邏輯層服務層,我希望保留所有業務邏輯規則包括業務邏輯驗證 in 業務邏輯層並使用服務層作爲包裝業務邏輯層Exception業務方法。

在決定是否使用異常的業務驗證規則或沒有,你可以考慮:

1)它的更好,你的業務方法的工作單元。他們應該完成一項完整的任務。所以它們最好包含驗證規則。這樣,您就可以重新使用這種業務邏輯層在不同服務層或使用工作相同單位在同一服務層的不同方法。如果您在業務邏輯層中引入業務驗證例外,您將不會面臨遺漏驗證或錯誤地使用其他驗證規則的風險,並且每個服務方法/操作都將爲您執行單個任務,並且將盡可能輕量級。

想想,當你可能需要公開WCF服務的一些客戶,或者例如,如果你可以使用ASP.NET MVC,而無需使用的WebAPI或當且僅當您要使用相同的邏輯在其他行動方法相同的WebAPI。

如果你把業務邏輯的Web API控制器驗證,創建WCF服務方法或創建MVC操作或其他服務的方法時,你可能會忘記申請驗證,也可以適用不同的規則錯誤驗證新服務層

2)考慮到第一個好處,您是否可以從顯示成功,失敗或在輸出中包含有關失敗原因的合適信息的方法返回有意義的值?

我相信這是不適合所有這些目標的方法。方法輸出是方法輸出,它應該是這種業務應用程序中的數據。它不應該有時是一種地位,有時候是數據或有時是消息。拋出異常將解決這個問題。

+0

你的回答非常好,它的完整性,我給你的賞金,但我的問題是更概念。其實我相信最好是從業務邏輯層中拋出異常,但我需要爭論來辯論這個問題,這是我的問題的目標,因爲我收到了關於我的同事的想法,比如「拋出異常導致糟糕的性能」或「拋出處理邏輯異常是一種代碼異味「,爲什麼我真的需要參數來討論這是最佳解決方案 – Balder

+0

感謝您的反饋,我試圖描述爲什麼在業務邏輯層中拋出異常更好。它不控制應用程序的流程。它使業務邏輯更加可重用,更可靠。它保證每個工作單位,始終以相同的方式工作。但是,如果您將業務驗證置於某個操作方法中,則可能會忘記在使用相同業務邏輯的另一個操作方法中應用相同的業務驗證。或者顯然如果你使用另一個服務層,你應該再次在新的服務層調用相同的業務驗證。 –

0

我認爲你應該在驗證控制器和服務,但驗證稍有不同的東西。特別是如果什麼開始只是一個API變成一個API,與MVC網站和WPF管理界面經常發生。

使用Validation Attributes和模型綁定爲數據提供了一次快速的「一次性」檢查。他們是否提供客戶更新的ID?他們是否爲相關實體提交了外鍵值?價格在0到1,000,000之間?如果你有一個網站,那麼你也可以開箱即可獲得客戶端驗證。至關重要的是,根本不需要連接到數據庫,因爲數據顯然是錯誤的。

服務中的驗證也是必需的,因爲您最終可能會有3或4個應用程序調用此服務,並且您希望編寫一次業務邏輯。一些驗證,例如。引用外鍵只能在數據庫中完成,但拋出異常沒有任何問題。你的API的消費者應該有權訪問有效值的範圍,網站的用戶應該從下拉等選擇,所以這種情況應該是例外