RequiredIf条件验证属性

zSy*_*sis 54 validationattribute asp.net-mvc-3

我正在寻找关于实现执行以下操作的验证属性的最佳方法的一些建议.

模型

public class MyInputModel 
{
    [Required]
    public int Id {get;set;}

    public string MyProperty1 {get;set;}
    public string MyProperty2 {get;set;}
    public bool MyProperty3 {get;set;}

}
Run Code Online (Sandbox Code Playgroud)

我想至少使用一个值得到prop1 prop2 prop3,如果prop3是填充它的唯一值,它不应该等于false.我将如何为此编写验证属性(s?)?

谢谢你的帮助!

Dan*_*nex 90

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

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

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(属性)的特定值的属性,您的其他属性必须为其进行验证

说你有以下内容:

public enum UserType
{
  Admin,
  Regular
}

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)

EDITED

有些人抱怨无论什么或不起作用,客户端都会发火.所以我修改了上面的代码,用javascript做了条件客户端验证.对于这种情况,您不需要注册适配器

 public class RequiredIfAttribute : ValidationAttribute, IClientValidatable
    {
        private String PropertyName { get; set; }
        private Object DesiredValue { get; set; }
        private readonly RequiredAttribute _innerAttribute;

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

        protected override ValidationResult IsValid(object value, ValidationContext context)
        {
            var dependentValue = context.ObjectInstance.GetType().GetProperty(PropertyName).GetValue(context.ObjectInstance, null);

            if (dependentValue.ToString() == DesiredValue.ToString())
            {
                if (!_innerAttribute.IsValid(value))
                {
                    return new ValidationResult(FormatErrorMessage(context.DisplayName), new[] { context.MemberName });
                }
            }
            return ValidationResult.Success;
        }

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationRule
            {
                ErrorMessage = ErrorMessageString,
                ValidationType = "requiredif",
            };
            rule.ValidationParameters["dependentproperty"] = (context as ViewContext).ViewData.TemplateInfo.GetFullHtmlFieldId(PropertyName);
            rule.ValidationParameters["desiredvalue"] = DesiredValue is bool ? DesiredValue.ToString().ToLower() : DesiredValue;

            yield return rule;
        }
    }
Run Code Online (Sandbox Code Playgroud)

最后是javascript(捆绑它和renderit ...把​​它放在自己的脚本文件中)

$.validator.unobtrusive.adapters.add('requiredif', ['dependentproperty', 'desiredvalue'], function (options) {
    options.rules['requiredif'] = options.params;
    options.messages['requiredif'] = options.message;
});

$.validator.addMethod('requiredif', function (value, element, parameters) {
    var desiredvalue = parameters.desiredvalue;
    desiredvalue = (desiredvalue == null ? '' : desiredvalue).toString();
    var controlType = $("input[id$='" + parameters.dependentproperty + "']").attr("type");
    var actualvalue = {}
    if (controlType == "checkbox" || controlType == "radio") {
        var control = $("input[id$='" + parameters.dependentproperty + "']:checked");
        actualvalue = control.val();
    } else {
        actualvalue = $("#" + parameters.dependentproperty).val();
    }
    if ($.trim(desiredvalue).toLowerCase() === $.trim(actualvalue).toLocaleLowerCase()) {
        var isValid = $.validator.methods.required.call(this, value, element, parameters);
        return isValid;
    }
    return true;
});
Run Code Online (Sandbox Code Playgroud)

您显然需要将不引人注意的验证jquery作为要求包含在内

  • 很棒的答案,对我来说非常有用! (3认同)
  • @Dan Hunex:在MVC4中,我无法在客户端正常工作,无论DesiredValue是什么,它都会启动验证.有任何帮助吗? (2认同)

jwa*_*zko 30

我知道这个话题是前一段时间被问过的,但是最近我遇到了类似的问题并发现了另一个问题,但在我看来,这是一个更完整的解决方案.我决定实现提供条件属性的机制,以根据逻辑表达式中定义的其他属性值和它们之间的关系来计算验证结果.

使用它,您可以通过以下方式获得您询问的结果:

[RequiredIf("MyProperty2 == null && MyProperty3 == false")]
public string MyProperty1 { get; set; }

[RequiredIf("MyProperty1 == null && MyProperty3 == false")]
public string MyProperty2 { get; set; }

[AssertThat("MyProperty1 != null || MyProperty2 != null || MyProperty3 == true")]
public bool MyProperty3 { get; set; }
Run Code Online (Sandbox Code Playgroud)

有关ExpressiveAnnotations库的更多信息,请访问此处.它应简化许多声明性验证案例,而无需在控制器内部编写其他特定于案例的属性或使用命令式验证方法.

  • @ H.Johnson:ad 1)应该通过NuGet自动将MvcUnobtrusiveValidatorProvider.dll添加到您的引用中.如果由于某种原因它不在那里 - 手动添加参考.广告2)为了使客户端验证工作,尽管ExpressiveAnnotations.dll,提到MvcUnobtrusiveValidatorProvider.dll也需要在那里.更多的表达式.annotations.validate.js应该包含在jquery验证文件下面的包中,并添加到指定的页面上(参见示例proj). (3认同)
  • 非常非常感谢这个图书馆。在可扩展性方面,它击败了所有其他人。 (2认同)
  • @ H.Johnson:这种例外不太可能发生.我假设你的代码中存在一个问题(也许你的类型含糊不清 - 你确定在Global.asax中你已经为适当的命名空间中的属性注册了适配器,即ExpressiveAnnotations.Attributes,而不是任何其他的?).为了帮助您,我需要更多信息,以上是为了更少.最后看看github上的[示例项目](https://github.com/JaroslawWaliszko/ExpressiveAnnotations/tree/master/src/ExpressiveAnnotations.MvcWebSample),并尝试研究区别的地方. (2认同)
  • @ H.Johnson:没问题,我很高兴它有所帮助;] (2认同)

Ade*_*rad 8

我让它在ASP.NET MVC 5上工作

我看到很多人对这段代码感兴趣并且感到痛苦,我知道这是第一次让人感到困惑和破坏.

笔记

  • 在服务器端和客户端上都使用MVC 5:D
  • 我根本没有安装"ExpressiveAnnotations"库.
  • 我正在接受" @Dan Hunex "中的原始代码,在上面找到他

修复此错误的提示

"System.Web.Mvc.RequiredAttributeAdapter类型必须有一个公共构造函数,它接受System.Web.Mvc.ModelMetadata,System.Web.Mvc.ControllerContext和ExpressiveAnnotations.Attributes.RequiredIfAttribute类型的三个参数参数名称:adapterType"

提示#1:确保您继承自' ValidationAttribute '而不是' RequiredAttribute '

 public class RequiredIfAttribute : ValidationAttribute, IClientValidatable { ...}
Run Code Online (Sandbox Code Playgroud)

提示#2:或者从' Global.asax '中删除整行,在较新版本的代码中完全不需要(在@Dan_Hunex编辑之后),是的,旧版本中必须使用此行. .

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

获取Javascript代码部分工作的提示

1-将代码放入新的js文件中(例如:requiredIfValidator.js)

2-扭曲$(document).ready(function(){........})中的代码;

3-包含JQuery验证库后包含我们的js文件,所以它现在看起来像这样:

@Scripts.Render("~/bundles/jqueryval")
<script src="~/Content/JS/requiredIfValidator.js"></script>
Run Code Online (Sandbox Code Playgroud)

4-编辑C#代码

rule.ValidationParameters["dependentproperty"] = (context as ViewContext).ViewData.TemplateInfo.GetFullHtmlFieldId(PropertyName);
Run Code Online (Sandbox Code Playgroud)

rule.ValidationParameters["dependentproperty"] = PropertyName;
Run Code Online (Sandbox Code Playgroud)

if (dependentValue.ToString() == DesiredValue.ToString())
Run Code Online (Sandbox Code Playgroud)

if (dependentValue != null && dependentValue.ToString() == DesiredValue.ToString())
Run Code Online (Sandbox Code Playgroud)

我的整个代码启动并运行

Global.asax中

没有什么可以添加到这里,保持清洁

requiredIfValidator.js

在〜/ content或〜/ scripts文件夹中创建此文件

    $.validator.unobtrusive.adapters.add('requiredif', ['dependentproperty', 'desiredvalue'], function (options)
{
    options.rules['requiredif'] = options.params;
    options.messages['requiredif'] = options.message;
});


$(document).ready(function ()
{

    $.validator.addMethod('requiredif', function (value, element, parameters) {
        var desiredvalue = parameters.desiredvalue;
        desiredvalue = (desiredvalue == null ? '' : desiredvalue).toString();
        var controlType = $("input[id$='" + parameters.dependentproperty + "']").attr("type");
        var actualvalue = {}
        if (controlType == "checkbox" || controlType == "radio") {
            var control = $("input[id$='" + parameters.dependentproperty + "']:checked");
            actualvalue = control.val();
        } else {
            actualvalue = $("#" + parameters.dependentproperty).val();
        }
        if ($.trim(desiredvalue).toLowerCase() === $.trim(actualvalue).toLocaleLowerCase()) {
            var isValid = $.validator.methods.required.call(this, value, element, parameters);
            return isValid;
        }
        return true;
    });
});
Run Code Online (Sandbox Code Playgroud)

_Layout.cshtml或View

@Scripts.Render("~/bundles/jqueryval")
<script src="~/Content/JS/requiredIfValidator.js"></script>
Run Code Online (Sandbox Code Playgroud)

RequiredIfAttribute.cs类

在项目的某个位置创建它,例如〜/ models/customValidation /

    using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace Your_Project_Name.Models.CustomValidation
{
    public class RequiredIfAttribute : ValidationAttribute, IClientValidatable
    {
        private String PropertyName { get; set; }
        private Object DesiredValue { get; set; }
        private readonly RequiredAttribute _innerAttribute;

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

        protected override ValidationResult IsValid(object value, ValidationContext context)
        {
            var dependentValue = context.ObjectInstance.GetType().GetProperty(PropertyName).GetValue(context.ObjectInstance, null);

            if (dependentValue != null && dependentValue.ToString() == DesiredValue.ToString())
            {
                if (!_innerAttribute.IsValid(value))
                {
                    return new ValidationResult(FormatErrorMessage(context.DisplayName), new[] { context.MemberName });
                }
            }
            return ValidationResult.Success;
        }

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationRule
            {
                ErrorMessage = ErrorMessageString,
                ValidationType = "requiredif",
            };
            rule.ValidationParameters["dependentproperty"] = PropertyName;
            rule.ValidationParameters["desiredvalue"] = DesiredValue is bool ? DesiredValue.ToString().ToLower() : DesiredValue;

            yield return rule;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

该模型

    using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using Your_Project_Name.Models.CustomValidation;

namespace Your_Project_Name.Models.ViewModels
{

    public class CreateOpenActivity
    {
        public Nullable<int> ORG_BY_CD { get; set; }

        [RequiredIf("ORG_BY_CD", "5", ErrorMessage = "Coordinator ID is required")] // This means: IF 'ORG_BY_CD' is equal 5 (for the example)  > make 'COR_CI_ID_NUM' required and apply its all validation / data annotations
        [RegularExpression("[0-9]+", ErrorMessage = "Enter Numbers Only")]
        [MaxLength(9, ErrorMessage = "Enter a valid ID Number")]
        [MinLength(9, ErrorMessage = "Enter a valid ID Number")]
        public string COR_CI_ID_NUM { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

风景

这里没什么值得注意的......

    @model Your_Project_Name.Models.ViewModels.CreateOpenActivity
@{
    ViewBag.Title = "Testing";
}

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>CreateOpenActivity</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        <div class="form-group">
            @Html.LabelFor(model => model.ORG_BY_CD, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ORG_BY_CD, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ORG_BY_CD, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.COR_CI_ID_NUM, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.COR_CI_ID_NUM, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.COR_CI_ID_NUM, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}
Run Code Online (Sandbox Code Playgroud)

我可以稍后上传一个项目样本......

希望这有用

谢谢