【问题标题】:MVC.net EF validation when using View Models使用视图模型时的 MVC.net EF 验证
【发布时间】:2011-09-27 05:41:00
【问题描述】:

我正在开发一个 MVC 应用程序,并且正在尝试实现一些验证。我已经构建了站点以使用 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);
}

【问题讨论】:

  • MVC:Controller=MVVM:ViewModel

标签: asp.net-mvc validation


【解决方案1】:
if (ModelState.IsValid)

这对于您的对象始终是正确的,因为它会寻找您的模型的有效性,即 AddressVM(您从视图中接收到,因此这是您的模型)并且没有任何验证器。 ModelState 不知道您已将此对象映射到其他实现验证的对象。您需要手动对其他对象运行验证并将验证错误添加到 ModelState。

如果你想把 this 分开,你可以在 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);
    }
} 

这样您的逻辑将保留在您的业务对象中,并且您的视图模型使用它而不需要它的副本或其他一些依赖项。

【讨论】:

    【解决方案2】:

    在您的情况下,Address 类和 AddressVm 没有相互绑定 - AutoMapper 不做验证工作,它只是复制值。所以你不会得到ModelState 填充和验证。

    我正在考虑两种解决方法

    1. AddressVm 上定义验证。如果是ModelState.IsValid,则将AddressVm 映射到Address 并保存。
    2. 您根本不需要AddressVm。将操作签名更改为期望 Address 参数。这样,ModelState.IsValid 将由验证系统自动填充(不是最佳解决方案)。

    理想情况下,应为特定场景定义 ViewModel。在您的情况下,我将定义AddAddressModel 使用它来添加地址,并仅定义创建地址所需的属性。然后,在 AddAddressModel 上定义验证并使用 mapper 将 ViewModel 映射到 Address 实例(所以,我更喜欢第一个解决方案,加上定义特定模型)。

    如果您需要可重用的验证器类,您可以查看FluentValidation。它也对 asp.net-mvc 有很好的支持。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-18
      • 2016-01-29
      • 2010-09-08
      • 2010-11-18
      • 2011-04-04
      相关资源
      最近更新 更多