C# 在同一字段上多次自定义验证属性

C# 在同一字段上多次自定义验证属性,c#,asp.net-mvc-3,jquery-validate,data-annotations,C#,Asp.net Mvc 3,Jquery Validate,Data Annotations,如何在同一字段上多次使用同一自定义验证属性,或仅为服务器端和客户端验证启用AllowMultiple=true 我有以下自定义验证属性: [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true, Inherited = true)] public class RequiredIfAttribute : ValidationAttribute,IClientV

如何在同一字段上多次使用同一自定义验证属性,或仅为服务器端和客户端验证启用AllowMultiple=true

我有以下自定义验证属性:

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, 
        AllowMultiple = true, Inherited = true)]
public class RequiredIfAttribute : ValidationAttribute,IClientValidatable
{
    public RequiredIfAttribute(string dependentProperties, 
     string dependentValues = "",
     string requiredValue = "val")
     {
     }
}
其中,在dependentProperties中,我可以指定多个由逗号分隔的从属属性;在DependentValue中,我可以指定应为哪些从属属性值进行验证;最后,在requiredValue中,我可以指定要验证的字段的预期值

在我的模型中有两个属性LandMark,PinCode,我希望使用如下验证:

public string LandMark { get; set; }
[RequiredIf("LandMark","XYZ","500500")]
[RequiredIf("LandMark", "ABC", "500505")]
public string PinCode { get; set; }
这里的值只是一个例子,好像我可以多次添加属性,并且没有任何编译错误,我已经在属性中实现了TypeID,如果我从服务器端删除客户端验证,它可以很好地工作。但当我在属性上实现IClientValidable时,它会给我一个错误:

“不引人注目的客户端验证规则中的验证类型名称必须唯一。”


有什么可以帮我解决的吗???

最后我自己在这里找到了答案。 请看下面的文章以获得解决方案

接受答案()中的链接有问题,其他人写了一个勘误表,我建议先阅读。上面的答案不处理继承。 我相信这个替代解决方案有一些优点(包括支持继承),但离完美的代码改进还有很长的路要走

该C#使用和

和JavaScript(在自定义验证器函数中)

函数集MultifliationValues(选项、规则名、值){
var i=0,此规则;
对于(;i10){抛出新引用错误(未定义ruleName+);}
setTimeout(addValidator方法,100);
返回;
}
if(!$.validator.methods[thisRule]){$.validator.addMethod(thisRule,$.validator.methods[ruleName]);}
})();
}
}
}
函数transformValidationValues(选项){
var规则=$.parseJSON(options.message),
propNames=[],p,utilObj,i=0,j,returnVar=[];
用于(选项参数中的p){
if(options.params.hasOwnProperty(p)){
utilObj={};
utilObj.key=p;
utilObj.vals=$.parseJSON(options.params[p]);
propNames.push(utilObj);
}
}
对于(;i
其使用示例如下: C#

使用系统;
使用System.Collections.Generic;
使用System.ComponentModel.DataAnnotations;
使用System.Text.RegularExpressions;
使用System.Web.Mvc;
命名空间DabTrial.Infrastructure.Validation
{
[AttributeUsage(AttributeTargets.Property,AllowMultiple=true,Inherited=true)]
公共类RegexCountAttribute:MultipleValidationAttribute
{
#区域成员
私有字符串\u defaultErrorMessageFormatString;
受保护的只读字符串_regexStr;
受保护的只读RegexOptions\u regexOpt;
私有整数_最小计数=0;
私有int _maximumCount=int.MaxValue;
#端区
#区域属性
公共整数最小计数
{
获取{return\u minimumCount;}
设置
{
如果(值<0){抛出新ArgumentOutOfRangeException();}
_最小计数=数值;
} 
}
公共整数最大计数
{
获取{return\u maximumCount;}
设置
{
如果(值<0){抛出新ArgumentOutOfRangeException();}
_最大计数=数值;
}
}
私有字符串DefaultErrorMessageFormatString
{
得到
{
if(_defaultErrorMessageFormatString==null)
{
_defaultErrorMessageFormatString=string.Format(
“{0}需要与regex{3}进行{0}{1}{2}匹配”,
最小计数>0?“+最小计数:”的最小值,
MinimumCount>0&&MaximumCount
  • 服务器
  • 客户
  • 服务器验证-多属性容易 如果您具有以下属性:

    [AttributeUsage(AttributeTargets.Property,AllowMultiple=true)]
    公共类RequirediftAttribute:ValidationAttribute
    并将其放在您的类属性上,如下所示:

    public class Client
    {
        public short ResidesWithCd { get; set; };
    
        [RequiredIf(nameof(ResidesWithCd), new[] { 99 }, "Resides with other is required.")]
        public string ResidesWithOther { get; set; }
    }
    然后ASP.NET将在生成时发出以下HTML:
    (只要
    &
    已启用)

    
    
    数据属性是我们将规则转储到客户端验证引擎的唯一工具,客户端验证引擎将
    HtmlAttributeProvider.Register((metadata) =>
    {
        return MultipleValidationAttribute.GetAttributes(metadata);
    });
    
    function setMultiValidationValues(options, ruleName, values) {
        var i = 0, thisRule;
        for (; i < values.length; i++) {
            thisRule = (i == 0) ? ruleName : ruleName + i;
            options.messages[thisRule] = values[i].message;
            delete values[i].message;
            options.rules[thisRule] = values[i];
            if (ruleName !== thisRule) {
                (function addValidatorMethod() {
                    var counter = 0;
                    if (!$.validator.methods[ruleName]) {
                        if (++counter > 10) { throw new ReferenceError(ruleName + " is not defined"); }
                        setTimeout(addValidatorMethod, 100);
                        return;
                    }
                    if (!$.validator.methods[thisRule]) { $.validator.addMethod(thisRule, $.validator.methods[ruleName]); }
                })();
            }
        }
    }
    function transformValidationValues(options) {
        var rules = $.parseJSON(options.message),
            propNames = [], p, utilObj,i = 0,j, returnVar=[];
        for (p in options.params) {
            if (options.params.hasOwnProperty(p)) {
                utilObj = {};
                utilObj.key = p;
                utilObj.vals = $.parseJSON(options.params[p]);
                propNames.push(utilObj);
            }
        }
        for (; i < rules.length; i++) {
            utilObj = {};
            utilObj.message = rules[i];
            for (j=0; j < propNames.length; j++) {
                utilObj[propNames[j].key] = propNames[j].vals[i];
            }
            returnVar.push(utilObj);
        }
        return returnVar;
    }
    
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Text.RegularExpressions;
    using System.Web.Mvc;
    
    namespace DabTrial.Infrastructure.Validation
    {
        [AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
        public class RegexCountAttribute : MultipleValidationAttribute
        {
            # region members
            private string _defaultErrorMessageFormatString;
            protected readonly string _regexStr;
            protected readonly RegexOptions _regexOpt;
            private int _minimumCount=0;
            private int _maximumCount=int.MaxValue;
            #endregion
            #region properties
            public int MinimumCount 
            {
                get { return _minimumCount; } 
                set 
                {
                    if (value < 0) { throw new ArgumentOutOfRangeException(); }
                    _minimumCount = value; 
                } 
            }
            public int MaximumCount
            {
                get { return _maximumCount; }
                set 
                {
                    if (value < 0) { throw new ArgumentOutOfRangeException(); }
                    _maximumCount = value; 
                }
            }
            private string DefaultErrorMessageFormatString
            {
                get
                {
                    if (_defaultErrorMessageFormatString == null)
                    {
                        _defaultErrorMessageFormatString = string.Format(
                            "{{0}} requires a {0}{1}{2} match(es) to regex {3}", 
                            MinimumCount>0?"minimum of "+ MinimumCount:"",
                            MinimumCount > 0 && MaximumCount< int.MaxValue? " and " : "",
                            MaximumCount<int.MaxValue?"maximum of "+ MaximumCount:"",
                            _regexStr);
                    }
                    return _defaultErrorMessageFormatString;
                }
                set
                {
                    _defaultErrorMessageFormatString = value;
                }
    
            }
            #endregion
            #region instantiation
            public RegexCountAttribute(string regEx, string defaultErrorMessageFormatString = null, RegexOptions regexOpt = RegexOptions.None)
            {
    #if debug
                if (minimumCount < 0) { throw new ArgumentException("the minimum value must be non-negative"); }
    #endif
                _regexStr = regEx;
                DefaultErrorMessageFormatString = defaultErrorMessageFormatString;
                _regexOpt = regexOpt;
            }
            #endregion
            #region methods
    
            protected override ValidationResult IsValid(object value,
                                                        ValidationContext validationContext)
            {
                var instr = (string)value;
                int matchCount = 0;
                if (MinimumCount > 0 && instr != null)
                {
                    Match match = new Regex(_regexStr,_regexOpt).Match(instr);
                    while (match.Success && ++matchCount < MinimumCount)
                    {
                       match = match.NextMatch();
                    }
                    if (MaximumCount != int.MaxValue)
                    {
                        while (match.Success && ++matchCount <= MaximumCount)
                        {
                            match = match.NextMatch();
                        }
                    }
                }
                if (matchCount >= MinimumCount && matchCount <=MaximumCount)
                {
                    return ValidationResult.Success;
                }
                string errorMessage = GetErrorMessage(validationContext.DisplayName);
                return new ValidationResult(errorMessage);
            }
            protected string GetErrorMessage(string displayName)
            {
                return ErrorMessage ?? string.Format(DefaultErrorMessageFormatString,
                    displayName,
                    MinimumCount);
            }
            private bool HasFlag(RegexOptions options, RegexOptions flag)
            {
                return ((options & flag) == flag);
            }
            private string RegexpModifier
            {
                get 
                {
                    string options = string.Empty;
                    if (HasFlag(_regexOpt, RegexOptions.IgnoreCase)) { options += 'i'; }
                    if (HasFlag(_regexOpt, RegexOptions.Multiline)) { options += 'm'; }
                    return options;
                }
            }
            public override IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata)
            {
                var returnVal = new ModelClientValidationRule {
                    ErrorMessage = GetErrorMessage(metadata.DisplayName),
                    ValidationType = "regexcount",
                };
                returnVal.ValidationParameters.Add("min",MinimumCount);
                returnVal.ValidationParameters.Add("max",MaximumCount);
                returnVal.ValidationParameters.Add("regex",_regexStr);
                returnVal.ValidationParameters.Add("regexopt", RegexpModifier);
                yield return returnVal;
            }
            #endregion
        }
        public class MinNonAlphanum : RegexCountAttribute
        {
            public MinNonAlphanum(int minimum) : base("[^0-9a-zA-Z]", GetDefaultErrorMessageFormatString(minimum)) 
            {
                this.MinimumCount = minimum;
            }
            private static string GetDefaultErrorMessageFormatString(int min)
            {
                if (min == 1)
                {
                    return "{0} requires a minimum of {1} character NOT be a letter OR number";
                }
                return "{0} requires a minimum of {1} characters NOT be a letter OR number";
            }
        }
        public class MinDigits : RegexCountAttribute
        {
            public MinDigits(int minimum) : base(@"\d", GetDefaultErrorMessageFormatString(minimum)) 
            {
                this.MinimumCount = minimum;
            }
            private static string GetDefaultErrorMessageFormatString(int min)
            {
                if (min == 1)
                {
                    return "{0} requires a minimum of {1} character is a number";
                }
                return "{0} requires a minimum of {1} characters are numbers";
            }
        }
    }
    
    $.validator.addMethod("regexcount", function (value, element, params) {
        var matches = (value.match(params.regex)||[]).length
        return  matches >= params.min && matches <= params.max;
    });
    $.validator.unobtrusive.adapters.add("regexcount", ["min", "max", "regex", "regexopt"], function (options) {
        var args = transformValidationValues(options), i=0;
        for (; i < args.length; i++) {
            args[i].regex = new RegExp(args[i].regex, args[i].regexopt);
            delete args[i].regexopt;
        }
        setMultiValidationValues(options, "regexcount", args);
    });
    
    public class Client
    {
        public short ResidesWithCd { get; set; };
    
        [RequiredIf(nameof(ResidesWithCd), new[] { 99 }, "Resides with other is required.")]
        public string ResidesWithOther { get; set; }
    }
    // hook up to client side validation
    $.validator.unobtrusive.adapters.add('requiredif', ['target', 'values'], function (options) {
        options.rules["requiredif"] = {
            id: '#' + options.params.target,
            values: JSON.parse(options.params.values)
        };
        options.messages['requiredif'] = options.message;
    });
    
    // test validity
    $.validator.addMethod('requiredif', function (value, element, params) {
        var targetHasCondValue = targetElHasValue(params.id, params.value);
        var requiredAndNoValue = targetHasCondValue && !value; // true -> :(
        var passesValidation = !requiredAndNoValue;            // true -> :)
        return passesValidation;
    }, '');