C# 在同一字段上多次自定义验证属性
如何在同一字段上多次使用同一自定义验证属性,或仅为服务器端和客户端验证启用AllowMultiple=true 我有以下自定义验证属性: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
[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;
}, '');