我对我的模型有一个价值,它必须在我的模型上的另外两个值的范围内。
例如:
public class RangeValidationSampleModel { int Value { get; set; } int MinValue { get; set; } int MaxValue { get; set; } }
当然,我不能将这些Min / MaxValues传递给我的DataAnnotations属性,因为它们必须是常量值。
我确定我需要建立自己的验证属性,但是我没有这么做,不能把我的想法放在一起,应该如何工作。
我搜索了大约一个小时,并且已经看到了各种解决方案来构建自定义验证,但是找不到任何东西来解决这个特殊的问题,使用MVC3不显眼的验证。
解决方法
您可以为此编写自定义验证属性:
public class DynamicRangeValidator : ValidationAttribute,IClientValidatable { private readonly string _minPropertyName; private readonly string _maxPropertyName; public DynamicRangeValidator(string minPropertyName,string maxPropertyName) { _minPropertyName = minPropertyName; _maxPropertyName = maxPropertyName; } protected override ValidationResult IsValid(object value,ValidationContext validationContext) { var minProperty = validationContext.ObjectType.GetProperty(_minPropertyName); var maxProperty = validationContext.ObjectType.GetProperty(_maxPropertyName); if (minProperty == null) { return new ValidationResult(string.Format("Unknown property {0}",_minPropertyName)); } if (maxProperty == null) { return new ValidationResult(string.Format("Unknown property {0}",_maxPropertyName)); } int minValue = (int)minProperty.GetValue(validationContext.ObjectInstance,null); int maxValue = (int)maxProperty.GetValue(validationContext.ObjectInstance,null); int currentValue = (int)value; if (currentValue <= minValue || currentValue >= maxValue) { return new ValidationResult( string.Format( ErrorMessage,minValue,maxValue ) ); } return null; } public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata Metadata,ControllerContext context) { var rule = new ModelClientValidationRule { ValidationType = "dynamicrange",ErrorMessage = this.ErrorMessage,}; rule.ValidationParameters["minvalueproperty"] = _minPropertyName; rule.ValidationParameters["maxvalueproperty"] = _maxPropertyName; yield return rule; } }
然后用它来装饰你的视图模型:
public class RangeValidationSampleModel { [DynamicRangeValidator("MinValue","MaxValue",ErrorMessage = "Value must be between {0} and {1}")] public int Value { get; set; } public int MinValue { get; set; } public int MaxValue { get; set; } }
那么你可以有一个控制器提供视图:
public class HomeController : Controller { public ActionResult Index() { return View(new RangeValidationSampleModel { Value = 5,MinValue = 6,MaxValue = 8 }); } [HttpPost] public ActionResult Index(RangeValidationSampleModel model) { return View(model); } }
并且当然是:
@model RangeValidationSampleModel <script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script> <script type="text/javascript"> $.validator.unobtrusive.adapters.add('dynamicrange',['minvalueproperty','maxvalueproperty'],function (options) { options.rules['dynamicrange'] = options.params; if (options.message != null) { $.validator.messages.dynamicrange = options.message; } } ); $.validator.addMethod('dynamicrange',function (value,element,params) { var minValue = parseInt($('input[name="' + params.minvalueproperty + '"]').val(),10); var maxValue = parseInt($('input[name="' + params.maxvalueproperty + '"]').val(),10); var currentValue = parseInt(value,10); if (isNaN(minValue) || isNaN(maxValue) || isNaN(currentValue) || minValue >= currentValue || currentValue >= maxValue) { var message = $(element).attr('data-val-dynamicrange'); $.validator.messages.dynamicrange = $.validator.format(message,maxValue); return false; } return true; },''); </script> @using (Html.BeginForm()) { <div> @Html.LabelFor(x => x.Value) @Html.EditorFor(x => x.Value) @Html.ValidationMessageFor(x => x.Value) </div> <div> @Html.LabelFor(x => x.MinValue) @Html.EditorFor(x => x.MinValue) </div> <div> @Html.LabelFor(x => x.MaxValue) @Html.EditorFor(x => x.MaxValue) </div> <button type="submit">OK</button> }
显然,自定义适配器注册应该在一个外部的javascript文件中执行,以避免污染视图,但为了这个目的和简洁的这篇文章我把它放在视图内。