不引人注目的validationC#MVC Razor

是否可以进行不显眼的validation以使字段成为必需字段,但仅当其他属性发生变化时?

例如

[Required] public Decimal Income {get; set;} [Required] public Decimal Tax {get; set;} //Required if tax or income changes public string ChangeReason {get; set;} 

我想过有多个后备存储字段并编写自定义validation器来比较它们,但是想知道是否有人有更好的建议?

自定义validation器是要走的路。 我不得不在不久前建立类似的东西。

我设置了一个隐藏值 – “已更改” – 只要用户修改了感兴趣的字段,就将其设置为true。

在感兴趣的2个属性上设置RequiredIfvalidation器:

  [RequiredIf("Changed", true, ErrorMessage = "Required")] 

RequiredIfvalidation器的代码如下所示:

 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 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 (ie 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; } } 

使用Javascript:

 ///  ///  $.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, eg 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; }); 

有可能的。 您可以编写自己的属性,以完全执行此操作。
它基本上需要两个步骤:

  1. 编写自己的属性,使其inheritanceValidationAttribute和实现IClientValidatable
  2. 编写一个Jqueryvalidation适配器来支持它

本文描述了一个很好的工作样本。
我使用类似的方法来创建依赖性validation(一个字段只有在填充了另一个字段时才有值)