2011-09-26 42 views
1

我正在研究一個MVC應用程序,我試圖實現一些驗證。我已經構建了使用EF進行存儲的站點以及使用automapper的一組視圖模型。MVC.net使用視圖模型時的EF驗證

我想添加一些驗證,我敢肯定會工作,如果我把它添加到視圖模型,但我假設這將是更好的與EF模型進行驗證,所以如果在未來,我創建另一個接口相同的驗證也適用。

首先是這是正確的方法,第二我如何讓MVC在保存對象之前實際測試驗證。目前它只是跳過我的EF驗證。

地址模式是自動生成的,所以我建立這個局部類以添加驗證:

public partial class Address : IValidatableObject 
{ 
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
    { 
     if (!string.IsNullOrWhiteSpace(this.AddressLine1) && 
      !string.IsNullOrWhiteSpace(this.AddressLine2) && 
      !string.IsNullOrWhiteSpace(this.AddressLine3) && 
      !string.IsNullOrWhiteSpace(this.Town) && 
      !string.IsNullOrWhiteSpace(this.City) && 
      !string.IsNullOrWhiteSpace(this.County) && 
      !string.IsNullOrWhiteSpace(this.Postcode)) 
      yield return new ValidationResult("Address cannot be blank."); 
    } 
} 

這與顯示名稱我的視圖模型類改變

public class AddressVM 
{ 
    public int? ID { get; set; } 

    [Display(Name = "Address line 1")] 
    public string AddressLine1 { get; set; } 

    [Display(Name = "Address line 2")] 
    public string AddressLine2 { get; set; } 

    [Display(Name = "Address line 3")] 
    public string AddressLine3 { get; set; } 

    [Display(Name = "Town")] 
    public string Town { get; set; } 

    [Display(Name = "City")] 
    public string City { get; set; } 

    [Display(Name = "County")] 
    public string County { get; set; } 

    [Display(Name = "Postcode")] 
    public string PostCode { get; set; } 
} 

這是我的控制器

public ActionResult AddAddress(AddressVM vm) 
{ 
    IncidentAddress theAddress = Mapper.Map<AddressVM, Address>(vm); 
    if (ModelState.IsValid) 
    { 
     UOW.Addresses.Add(theAddress); 
     UOW.Save(); 
    } 
    return PartialView("AddressVM-edit", vm); 
} 
+0

MVC:Controller = MVVM:ViewModel – Will

回答

1
if (ModelState.IsValid) 

這對於你的對象來說總是如此,因爲它會查找你的模型的有效性,這是AddressVM(你從視圖中接收到,因此這是你的模型)並且沒有任何驗證器。模型狀態不知道你已經將這個對象映射到實現驗證的其他對象。您需要手動在其他對象上運行驗證並向ModelState添加驗證錯誤。

如果你想分開這個,你可以在AddressVM上實現IValidatableObject,並且通過創建Address的一個實例,從AddressVM(this)映射它並返回它的Validate方法的結果在內部執行驗證。您也可以將同一構造的Address對象作爲屬性公開,並使用它來執行實體操作。 AddressVM的

例子:

public class AddressVM : IValidatableObject  
{ 
    public int? ID { get; set; } 

    [Display(Name = "Address line 1")] 
    public string AddressLine1 { get; set; } 

    [Display(Name = "Address line 2")] 
    public string AddressLine2 { get; set; } 

    [Display(Name = "Address line 3")] 
    public string AddressLine3 { get; set; } 

    [Display(Name = "Town")] 
    public string Town { get; set; } 

    [Display(Name = "City")] 
    public string City { get; set; } 

    [Display(Name = "County")] 
    public string County { get; set; } 

    [Display(Name = "Postcode")] 
    public string PostCode { get; set; } 


    //// I added this and interface in class definition: 

    public IncidentAddress GetIncidentAddress() 
    { 
     return Mapper.Map<AddressVM, Address>(this); 
    } 

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)  
    { 
     return this.GetIncidentAddress().Validate(validationContext); 
    } 
} 

這樣,你的邏輯停留在你的業務對象,並且您的視圖模型使用它,而無需它的副本或其他一些依賴。

1

Address class和AddressVm在你的情況下沒有相互綁定 - AutoMapper不做驗證的東西,它只是複製值。所以你沒有得到ModelState填充和驗證執行。

這裏有兩種解決方法我在想

  1. 定義上AddressVm的驗證。如果ModelState.IsValid,則將AddressVm映射到Address並保存。
  2. 根本不需要AddressVm。更改操作簽名以期望Address參數。那樣,ModelState.IsValid將被驗證系統自動填充(不是最好的解決方案)。

理想情況下,應爲特定場景定義ViewModels。在你的情況下,我會定義AddAddressModel,使用它只有增加地址和定義只有屬性需要創建地址。然後,在AddAddressModel上定義驗證並使用映射器將ViewModel映射到Address實例(因此,我更喜歡第一個解決方案,並定義了特定的模型)。

如果您需要可重用的驗證程序類,則可以查看FluentValidation。它也很好的支持asp.net-mvc。