ASP.NET MVC条件验证

Pet*_*nar 122 c# forms validation asp.net-mvc

如何使用数据注释对模型进行条件验证?

例如,假设我们有以下模型(Person和Senior):

public class Person
{
    [Required(ErrorMessage = "*")]
    public string Name
    {
        get;
        set;
    }

    public bool IsSenior
    {
        get;
        set;
    }

    public Senior Senior
    {
        get;
        set;
    }
}

public class Senior
{
    [Required(ErrorMessage = "*")]//this should be conditional validation, based on the "IsSenior" value
    public string Description
    {
        get;
        set;
    }
}
Run Code Online (Sandbox Code Playgroud)

以下观点:

<%= Html.EditorFor(m => m.Name)%>
<%= Html.ValidationMessageFor(m => m.Name)%>

<%= Html.CheckBoxFor(m => m.IsSenior)%>
<%= Html.ValidationMessageFor(m => m.IsSenior)%>

<%= Html.CheckBoxFor(m => m.Senior.Description)%>
<%= Html.ValidationMessageFor(m => m.Senior.Description)%>
Run Code Online (Sandbox Code Playgroud)

我希望成为"Senior.Description"属性条件必需字段,基于"IsSenior"的选择(真 - >必需).如何使用数据注释在ASP.NET MVC 2中实现条件验证?

vip*_*naz 143

有一种更好的方法可以在MVC3中添加条件验证规则.让您的模型继承IValidatableObject并实现Validate方法:

public class Person : IValidatableObject
{
    public string Name { get; set; }
    public bool IsSenior { get; set; }
    public Senior Senior { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
    { 
        if (IsSenior && string.IsNullOrEmpty(Senior.Description)) 
            yield return new ValidationResult("Description must be supplied.");
    }
}
Run Code Online (Sandbox Code Playgroud)

http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx上查看更多描述

  • 如果您实施它,请执行此操作 - 请参阅http://www.falconwebtech.com/post/MVC3-Custom-Validation-Attributes-for-Client-Server-Side-Validation-with-Unobtrusive-Ajax的完整示例 (7认同)
  • http://www.falconwebtech.com/post/MVC3-Custom-Validation-Attributes-for-Client-Server-Side-Validation-with-Unobtrusive-Ajax - @viperguynaz这不起作用 (4认同)
  • 我知道这是一个较旧的线程,但为了完成 - @viperguynaz - 将错误绑定到特定属性(例如,用于显示客户端模型绑定验证错误),请改用重载方法。"yield return new ValidationResult("ErrorMessage.", new[] {"PutNameOfPropertyHere"}); 如果没有这个,验证错误是通用的,并且需要在视图中显示一个包罗万象的警告标签。 (3认同)
  • +1,实现IValidateObject真棒!:)但是,你的括号几乎没有关闭(我编辑它们来解决它). (2认同)
  • 不幸的是,微软把它放在错误的层 - 验证是业务逻辑,这个接口在System.Web DLL中.为了使用它,您必须为业务层提供对表示技术的依赖. (2认同)
  • @RayLoveless 你应该调用`ModelState.IsValid` - 不要直接调用 Validate (2认同)

Pet*_*nar 61

我通过处理控制器包含的"ModelState"字典解决了这个问题.ModelState字典包括必须验证的所有成员.

这是解决方案:

如果您需要基于某个字段实现条件验证(例如,如果A = true,则需要B),同时保持属性级别错误消息传递(对于对象级别的自定义验证器不是这样),您可以实现此目的通过处理"ModelState",只需从中删除不需要的验证.

......在某些班级......

public bool PropertyThatRequiredAnotherFieldToBeFilled
{
  get;
  set;
}

[Required(ErrorMessage = "*")] 
public string DepentedProperty
{
  get;
  set;
}
Run Code Online (Sandbox Code Playgroud)

......继续......

......在某些控制器动作中......

if (!PropertyThatRequiredAnotherFieldToBeFilled)
{
   this.ModelState.Remove("DepentedProperty");
}
Run Code Online (Sandbox Code Playgroud)

...

有了这个,我们实现了条件验证,同时保留了其他所有内容.


更新:

这是我的最终实现:我在模型上使用了一个接口,并使用了action属性来验证实现所述接口的模型.接口规定了Validate(ModelStateDictionary modelState)方法.action上的属性只调用IValidatorSomething上的Validate(modelState).

我不想让这个答案复杂化,所以我没有提到最终的实现细节(最后,在生产代码中的问题).

  • 缺点是验证逻辑的一部分位于模型中,另一部分位于控制器中. (16认同)
  • -1与客户端验证不兼容 (4认同)
  • @Aaron:我很高兴你喜欢解决方案,但不幸的是这个解决方案不适用于客户端验证(因为每个验证属性都需要它的JavaScript实现).您可以使用"远程"属性来帮助自己,因此只会发出Ajax调用来验证它. (2认同)

Dan*_*nex 33

我昨天遇到了同样的问题但是我以一种非常干净的方式做到了这一点,它适用于客户端和服务器端验证.

条件:根据模型中其他属性的值,您需要创建另一个属性.这是代码

public class RequiredIfAttribute : RequiredAttribute
{
    private String PropertyName { get; set; }
    private Object DesiredValue { get; set; }

    public RequiredIfAttribute(String propertyName, Object desiredvalue)
    {
        PropertyName = propertyName;
        DesiredValue = desiredvalue;
    }

    protected override ValidationResult IsValid(object value, ValidationContext context)
    {
        Object instance = context.ObjectInstance;
        Type type = instance.GetType();
        Object proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null);
        if (proprtyvalue.ToString() == DesiredValue.ToString())
        {
            ValidationResult result = base.IsValid(value, context);
            return result;
        }
        return ValidationResult.Success;
    }
}
Run Code Online (Sandbox Code Playgroud)

这里PropertyName是您要在其上创建条件的属性DesiredValue是PropertyName(property)的特定值,您的其他属性必须为其进行验证

说你有以下

public class User
{
    public UserType UserType { get; set; }

    [RequiredIf("UserType", UserType.Admin, ErrorMessageResourceName = "PasswordRequired", ErrorMessageResourceType = typeof(ResourceString))]
    public string Password
    {
        get;
        set;
    }
}
Run Code Online (Sandbox Code Playgroud)

最后但并非最不重要,为您的属性注册适配器,以便它可以进行客户端验证(我把它放在global.asax,Application_Start)

 DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredIfAttribute),typeof(RequiredAttributeAdapter));
Run Code Online (Sandbox Code Playgroud)

  • 这仅适用于链接博客所述的服务器端 (2认同)
  • 我设法在MVC5的客户端使用它,但是在客户端它会激活验证,无论DesiredValue是什么. (2认同)

Kor*_*yem 29

我一直在使用这个神奇的nuget做动态注释ExpressiveAnnotations

您可以验证您可以梦想的任何逻辑:

public string Email { get; set; }
public string Phone { get; set; }
[RequiredIf("Email != null")]
[RequiredIf("Phone != null")]
[AssertThat("AgreeToContact == true")]
public bool? AgreeToContact { get; set; }
Run Code Online (Sandbox Code Playgroud)

  • ExpressiveAnnotation库是这里所有答案中最灵活,最通用的解决方案.感谢分享! (3认同)
  • 我一直在试图寻找一个坚实的日子的解决方案.ExpressiveAnnotations看起来像是我的修复! (2认同)

Pav*_*uva 17

您可以通过从ModelState中删除错误来有条件地禁用验证器:

ModelState["DependentProperty"].Errors.Clear();
Run Code Online (Sandbox Code Playgroud)


小智 8

谢谢梅里特:)

我刚刚将其更新为MVC 3,以防有人发现它有用; http://blogs.msdn.com/b/simonince/archive/2011/02/04/conditional-validation-in-asp-net-mvc-3.aspx

西蒙


boj*_*ngo 6

现在有一个框架可以开箱即用这个条件验证(以及其他方便的数据注释验证):http: //foolproof.codeplex.com/

具体来说,看一下[RequiredIfTrue("IsSenior")]验证器.您将它直接放在要验证的属性上,这样就可以获得与"Senior"属性关联的验证错误的所需行为.

它以NuGet包的形式提供.