低调验证C#MVC Razor
是否有可能进行不引人注目的验证,以使字段成为必需字段,但仅当其他属性发生变化时 比如说低调验证C#MVC Razor,c#,asp.net-mvc-3,C#,Asp.net Mvc 3,是否有可能进行不引人注目的验证,以使字段成为必需字段,但仅当其他属性发生变化时 比如说 [Required] public Decimal Income {get; set;} [Required] public Decimal Tax {get; set;} //Required if tax or income changes public string ChangeReason {get; set;} 我曾考虑过使用多个备份存储字段并编写一个自定义验证器来比较这些字段,但我想知道是否有人
[Required]
public Decimal Income {get; set;}
[Required]
public Decimal Tax {get; set;}
//Required if tax or income changes
public string ChangeReason {get; set;}
我曾考虑过使用多个备份存储字段并编写一个自定义验证器来比较这些字段,但我想知道是否有人有更好的建议?这是可能的。您可以编写自己的属性,以便准确地执行此操作。
它基本上需要两个步骤:
我使用了类似的方法来创建依赖项验证(一个字段只有在另一个字段已填充时才能有值)自定义验证程序是一种方法。不久前,我不得不建造类似的东西 我设置了一个隐藏值——“Changed”——每当用户修改感兴趣的字段时,将其设置为true 在2个感兴趣的属性上设置RequiredIf验证器:
[RequiredIf("Changed", true, ErrorMessage = "Required")]
RequiredIf验证器的代码如下所示:
public class RequiredIfAttribute : ValidationAttribute, IClientValidatable
{
private RequiredAttribute _innerAttribute = new RequiredAttribute();
public string DependentProperty { get; set; }
public object TargetValue { get; set; }
public RequiredIfAttribute(string dependentProperty, object targetValue)
{
this.DependentProperty = dependentProperty;
this.TargetValue = targetValue;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
// get a reference to the property this validation depends upon
var containerType = validationContext.ObjectInstance.GetType();
var field = containerType.GetProperty(this.DependentProperty);
if (field != null)
{
// get the value of the dependent property
var dependentvalue = field.GetValue(validationContext.ObjectInstance, null);
// compare the value against the target value
if ((dependentvalue == null && this.TargetValue == null) ||
(dependentvalue != null && dependentvalue.Equals(this.TargetValue)))
{
// match => means we should try validating this field
if (!_innerAttribute.IsValid(value))
// validation failed - return an error
return new ValidationResult(this.ErrorMessage, new[] { validationContext.MemberName });
}
}
return null;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule()
{
ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
ValidationType = "requiredif",
};
string depProp = BuildDependentPropertyId(metadata, context as ViewContext);
// find the value on the control we depend on;
// if it's a bool, format it javascript style
// (the default is True or False!)
string targetValue = (this.TargetValue ?? "").ToString();
if (this.TargetValue.GetType() == typeof(bool))
targetValue = targetValue.ToLower();
rule.ValidationParameters.Add("dependentproperty", depProp);
rule.ValidationParameters.Add("targetvalue", targetValue);
yield return rule;
}
private string BuildDependentPropertyId(ModelMetadata metadata, ViewContext viewContext)
{
// build the ID of the property
string depProp = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(this.DependentProperty);
// unfortunately this will have the name of the current field appended to the beginning,
// because the TemplateInfo's context has had this fieldname appended to it. Instead, we
// want to get the context as though it was one level higher (i.e. outside the current property,
// which is the containing object (our Person), and hence the same level as the dependent property.
var thisField = metadata.PropertyName + "_";
if (depProp.StartsWith(thisField))
// strip it off again
depProp = depProp.Substring(thisField.Length);
return depProp;
}
}
公共类requireditAttribute:ValidationAttribute,IClientValidable
{
私有RequiredAttribute_innerAttribute=新RequiredAttribute();
公共字符串依赖属性{get;set;}
公共对象TargetValue{get;set;}
public requirediftAttribute(字符串相关属性,对象targetValue)
{
this.DependentProperty=DependentProperty;
this.TargetValue=TargetValue;
}
受保护的重写ValidationResult有效(对象值,ValidationContext ValidationContext)
{
//获取对此验证所依赖的属性的引用
var containerType=validationContext.ObjectInstance.GetType();
var field=containerType.GetProperty(this.DependentProperty);
如果(字段!=null)
{
//获取依赖属性的值
var dependentvalue=field.GetValue(validationContext.ObjectInstance,null);
//将该值与目标值进行比较
if((dependentvalue==null&&this.TargetValue==null)||
(dependentvalue!=null&&dependentvalue.Equals(this.TargetValue)))
{
//match=>表示我们应该尝试验证此字段
如果(!\u innerAttribute.IsValid(值))
//验证失败-返回错误
返回新的ValidationResult(this.ErrorMessage,new[]{validationContext.MemberName});
}
}
返回null;
}
公共IEnumerable GetClientValidationRules(ModelMetadata元数据、ControllerContext上下文)
{
var rule=new ModelClientValidationRule()
{
ErrorMessage=FormatErrorMessage(metadata.GetDisplayName()),
ValidationType=“requiredif”,
};
string depProp=BuildDependentPropertyId(元数据,上下文为ViewContext);
//找到我们所依赖的控件的值;
//如果是bool,则将其格式化为javascript样式
//(默认值为True或False!)
字符串targetValue=(this.targetValue???).ToString();
if(this.TargetValue.GetType()==typeof(bool))
targetValue=targetValue.ToLower();
rule.ValidationParameters.Add(“dependentproperty”,depProp);
规则.ValidationParameters.Add(“targetvalue”,targetvalue);
收益率-收益率规则;
}
私有字符串BuildDependentPropertyId(ModelMetadata元数据,ViewContext)
{
//生成属性的ID
string depProp=viewContext.ViewData.TemplateInfo.GetFullHtmlFieldDid(this.DependentProperty);
//不幸的是,这将在开头追加当前字段的名称,
//因为TemplateInfo的上下文已经附加了这个字段名
//想要获得更高一级的上下文(即在当前属性之外,
//它是包含对象(我们的人),因此与从属属性处于同一级别。
var thisField=metadata.PropertyName+“\uux”;
if(depProp.StartsWith(此字段))
//再把它剥掉
depProp=depProp.Substring(thisField.Length);
返回depProp;
}
}
Javascript:
/// <reference path="jquery-1.4.4-vsdoc.js" />
/// <reference path="jquery.validate.unobtrusive.js" />
$.validator.addMethod('requiredif',
function (value, element, parameters) {
var id = '#' + parameters['dependentproperty'];
// get the target value (as a string,
// as that's what actual value will be)
var targetvalue = parameters['targetvalue'];
targetvalue =
(targetvalue == null ? '' : targetvalue).toString();
// get the actual value of the target control
// note - this probably needs to cater for more
// control types, e.g. radios
var control = $(id);
var controltype = control.attr('type');
var actualvalue =
controltype === 'checkbox' ?
control.attr('checked').toString() :
control.val();
// if the condition is true, reuse the existing
// required field validator functionality
if (targetvalue === actualvalue)
return $.validator.methods.required.call(
this, value, element, parameters);
return true;
}
);
$.validator.unobtrusive.adapters.add(
'requiredif',
['dependentproperty', 'targetvalue'],
function (options) {
options.rules['requiredif'] = {
dependentproperty: options.params['dependentproperty'],
targetvalue: options.params['targetvalue']
};
options.messages['requiredif'] = options.message;
});
//
///
$.validator.addMethod('requiredif',
函数(值、元素、参数){
变量id='#'+参数['dependentproperty'];
//获取目标值(作为字符串,
//因为这就是实际价值)
var targetvalue=参数['targetvalue'];
目标值=
(targetvalue==null?“”:targetvalue).toString();
//获取目标控件的实际值
//注-这可能需要满足更多的需求
//控制类型,例如无线电
变量控制=$(id);
var controltype=control.attr('type');
var实际价值=
controltype==“复选框”?
control.attr('checked').toString():
control.val();
//如果条件为true,则重用现有的
//必需的字段验证器功能
如果(targetvalue==实际值)
返回$.validator.methods.required.call(
该参数、值、元素、参数);
返回true;
}
);
$.validator.unobtrusive.adapters.add(
“requiredif”,
['dependentproperty','targetvalue'],
功能(选项){
选项.规则['requiredif']={
dependentproperty:options.params['dependentproperty'],
targetvalue:options.params['targetvalue']
};
options.messages['requiredif']=options.message;
});
这里有一个类似的问题和一个解决方案:如果您将嵌套的EditorFor helpers与此代码一起使用,客户端验证将失败。依赖属性的id将以更高的属性名称作为前缀,这里的这一行:if(depProp.StartsWith(thisField))
将始终为false。因此,通过