2012-01-04 64 views
2

我希望能夠從我的服務類中執行驗證。我有一個控制器的動作,看起來是這樣的:將模型驗證移動到服務類 - ASP.NET MVC

public ActionResult Edit(Post post) 
{ 
    if(!ModelState.IsValid) 
     return View(); 

    _postDataService.SavePost(post); 

    return View("Index"); 
} 

我不喜歡的事實,我_postDataService.SavePost()可以保存無效數據,我想在模型驗證移動到我的_postDataService.SavePost( ) 方法。我的問題是什麼是最優雅的方式來做到這一點?如果我將我的模型驗證移動到我的Service方法,那麼如何將模型錯誤返回給我的控制器?最後,模型驗證會在哪裏進行,如電子郵件地址的唯一性,因爲它需要一些數據訪問權限?在我看過的所有類似問題中,他們都沒有提供直接的方法來做到這一點。

我也認爲this解決方案,但這篇文章是舊的,我有一種感覺它不是最新的。

+0

是的,你提到的文章很舊,但其中提出的概念仍然存在 – 2012-01-04 11:31:59

回答

3

我假設你正在通過將屬性放在Post模型/實體類中進行驗證。如果是這樣,你可以這樣做在你的服務層驗證:

var results = new List<ValidationResult>(); 
var isValid = Validator.TryValidateObject(post, 
    new ValidationContext(post, null, null), results, true); 

這主要是當它驗證和配置的ModelState對象控制器/動作默認模型綁定器做什麼。

這種方法的美妙之處在於,您不必從服務層返回驗證錯誤。你只需要依靠默認的modelbinder自動完成上面的代碼。如果有人試圖在不檢查ModelState.IsValid的情況下調用該操作,只需讓您的服務方法拋出異常來提醒他們即可。

評論

是的,我的回答建議做兩次確認後更新。

我感覺如何?我不介意。我們使用實體框架4.1與MVC,並且不使用MVC中的實體。相反,我們使用automapper來將實體DTO到單獨的視圖模型層中。我們的EF實體也用ValidationAttributes裝飾,EF在任何DbContext.SaveChanges()操作期間自動評估。我們在viewmodel類的屬性上應用了非常相似的驗證屬性。這可能看起來不幹,並且確實存在重疊,但在某些情況下,UI側的驗證屬性可能與域模型中的驗證屬性不同。

我們不在服務層進行驗證。我們的服務層只是一個應用程序流程協調員,並且不負責任何業務規則。但是,驗證在我們的應用程序中仍然發生兩次首先,通過默認模型聯編程序,針對視圖模型驗證規則。然後,如果交易使其成爲EF,則對實體執行驗證。所以我們實際上正在驗證2個單獨的圖層。

如果你考慮一下,你真的在​​解決2個不同的問題。在UI中,您希望MVC向用戶顯示驗證消息。 ModelState對此很好,因爲它很好地與MVC驗證(模型綁定/ jQuery /不顯眼/客戶端驗證/等)掛鉤。

相反,在域中,您正在保護您的數據完整性並執行業務規則。該域不關心向用戶顯示消息。衆所周知,客戶端可能是一臺機器,WCF服務或其他東西。域的作用是防止事務發生,並且(在我們的情況下)拋出異常,而不是悄悄地試圖與客戶端「合作」。

+0

謝謝!我總是想知道模型粘結劑在做什麼。所以你說保持if(!ModelState.IsValid)返回View();在我的操作控制器中,但通過在我的Service方法中再次調用驗證邏輯來​​防止輸入無效數據。您如何看待這樣一個事實,即當沒有驗證錯誤時,驗證會執行兩次? – enamrik 2012-01-04 15:39:21

+0

嗨OliveHour,你的解決方案對於簡單的驗證很好,但可以說,對於上面的Post對象,我們必須驗證Subject屬性是唯一的;這將涉及到DB的旅程。我不認爲這屬於控制器,服務層或模型(即實現IValidatableObject),你認爲如何? – 2012-01-22 03:49:42