MVC自定义validation:比较两个date

我创build了一个自定义ValidationAttribute来比较两个date,并确保第二个date大于第一个date:

public sealed class IsDateAfter : ValidationAttribute, IClientValidatable { private readonly string testedPropertyName; private readonly bool allowEqualDates; public IsDateAfter(string testedPropertyName, bool allowEqualDates = false) { this.testedPropertyName = testedPropertyName; this.allowEqualDates = allowEqualDates; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var propertyTestedInfo = validationContext.ObjectType.GetProperty(this.testedPropertyName); if (propertyTestedInfo == null) { return new ValidationResult(string.Format("unknown property {0}", this.testedPropertyName)); } var propertyTestedValue = propertyTestedInfo.GetValue(validationContext.ObjectInstance, null); if (value == null || !(value is DateTime)) { return ValidationResult.Success; } if (propertyTestedValue == null || !(propertyTestedValue is DateTime)) { return ValidationResult.Success; } // Compare values if ((DateTime)value >= (DateTime)propertyTestedValue) { if (this.allowEqualDates) { return ValidationResult.Success; } if ((DateTime)value > (DateTime)propertyTestedValue) { return ValidationResult.Success; } } return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); } public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { var rule = new ModelClientValidationRule { ErrorMessage = this.ErrorMessageString, ValidationType = "isdateafter" }; rule.ValidationParameters["propertytested"] = this.testedPropertyName; rule.ValidationParameters["allowequaldates"] = this.allowEqualDates; yield return rule; } 

CalendarEntry类:…

 public virtual DateTime StartDate { get; set; } [IsDateAfter("StartDate", true, ErrorMessage="End date needs to be after start date")] public virtual DateTime EndDate { get; set; } 

视图:

 $.validator.unobtrusive.adapters.add( 'isdateafter', ['propertytested', 'allowequaldates'], function (options) { options.rules['isdateafter'] = options.params; options.messages['isdateafter'] = options.message; }); $.validator.addMethod("isdateafter", function(value, element, params) { alert(params.propertytested); var startdatevalue = $('input[name="' + params.propertytested + '"]').val(); if (!value || !startdatevalue) return true; return (params.allowequaldates) ? Date.parse(startdatevalue) <= Date.parse(value) : Date.parse(startdatevalue) < Date.parse(value); }, ''); 

CalendarEntry不包裹在另一个类中时,这工作正常。 不过,当我使用这样的视图模型:

  public class TrainingDateEditViewModel { #region Properties /// <summary> /// Gets or sets CalendarEntry. /// </summary> public CalendarEntry CalendarEntry { get; set; } .... 

客户端validation不再起作用,因为生成的html输出是这样的:

 <input type="text" value="" name="CalendarEntry.EndDate" id="CalendarEntry_EndDate" data-val-isdateafter-propertytested="StartDate" data-val-isdateafter-allowequaldates="True" data-val-isdateafter="End date needs to be after start date" data-val="true"> 

而且

 data-val-isdateafter-propertytested="StartDate" and IT SHOULD BE: "CalendarEntry.StartDate". 

我将如何使它知道绑定到“CalendarEntry.StartDate”rule.ValidationParameters [“propertytested”] = this.testedPropertyName; //这里应该是完整的名字? 怎么样??

谢谢

您需要修改您的客户端脚本以检查被testing元素的前缀,并将前缀(如果有)添加到select器中,如下所示:

 $.validator.addMethod("isdateafter", function(value, element, params) { var parts = element.name.split("."); var prefix = ""; if (parts.length > 1) prefix = parts[0] + "."; var startdatevalue = $('input[name="' + prefix + params.propertytested + '"]').val(); if (!value || !startdatevalue) return true; return (params.allowequaldates) ? Date.parse(startdatevalue) <= Date.parse(value) : Date.parse(startdatevalue) < Date.parse(value); }); 

不要忘记在代码中包含客户端。 我花了几个小时才发现这是失踪的!

 (function ($) { // your code here.. })(jQuery); 

只是为了解决counsellorben的javascript中的一个小错误:“(params.allowequaldates)”将被解释为一个string(其值将为“False”或“True”),但该string将始终评估为true,从而始终允许相同的date。 如果您还希望允许您的对象的嵌套级别超过1,那么您将获得:

 $.validator.addMethod("isdateafter", function(value, element, params) { var parts = element.name.split("."); var prefix = ""; for (var i = 0; i < parts.length - 1; i++) prefix = parts[i] + "."; var startdatevalue = $('input[name="' + prefix + params.propertytested + '"]').val(); if (!value || !startdatevalue) return true; var allowequal = params.allowequaldates.toLowerCase === "true"; return allowequal ? Date.parse(startdatevalue) <= Date.parse(value) : Date.parse(startdatevalue) < Date.parse(value); }); 

在最后一个答案中,有一些调用toLowerCase时遗漏了一些括号,这里是一个准备好文档的更新版本和$ .validator.unobtrusive …-部分:

 $(function () { $.validator.addMethod("isdateafter", function(value, element, params) { var parts = element.name.split("."); var prefix = ""; for (var i = 0; i < parts.length - 1; i++) { prefix = parts[i] + "."; } var startdatevalue = $('input[name="' + prefix + params.propertytested + '"]').val(); if (!value || !startdatevalue) return true; var allowequal = params.allowequaldates.toLowerCase() === "true"; return allowequal ? Date.parse(startdatevalue) <= Date.parse(value) : Date.parse(startdatevalue) < Date.parse(value); }); $.validator.unobtrusive.adapters.add('isdateafter', ['propertytested', 'allowequaldates'], function (options) { options.rules['isdateafter'] = options.params; options.messages['isdateafter'] = options.message; }); });