我正在研究MVC应用程序,我正在尝试实现一些验证。我已经建立了网站使用EF存储和一组使用automapper的视图模型。
我想添加一些验证,如果我将它添加到View Models中我肯定会有效但是我假设将验证放入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 :(得分:1)
if (ModelState.IsValid)
对于您的对象,这将始终如此,因为它将查找模型的有效性,即AddressVM(您从视图中收到,因此这是您的模型)并且没有任何验证器。 ModelState不知道您已将此对象映射到实现验证的其他对象。您需要手动对其他对象运行验证,并将验证错误添加到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);
}
}
这样,您的逻辑就会停留在您的业务对象中,并且您的viewmodel会使用它而不会复制它或其他依赖项。
答案 1 :(得分:1)
Address
类和AddressVm
在您的情况下不会相互绑定 - AutoMapper不会执行验证,它只是复制值。因此,您不会执行ModelState
填充和验证。
我正在考虑两种解决方法
AddressVm
上定义验证。如果是ModelState.IsValid
,请将AddressVm
映射到Address
并保存。AddressVm
。更改操作签名以期望Address
参数。这样,ModelState.IsValid
将由验证系统自动填充(不是最佳解决方案)。理想情况下,应针对特定方案定义ViewModel。在您的情况下,我将定义AddAddressModel
,仅使用 来添加地址,并仅定义创建地址所需的属性。然后,在AddAddressModel
上定义验证并使用mapper将ViewModel映射到Address
实例(所以,我更喜欢第一个解决方案,再加上定义特定模型)。
如果您需要可重复使用的验证程序类,可以查看FluentValidation。它也得到了asp.net-mvc的良好支持。