MVC 自定义验证:比较两个日期

Posted

技术标签:

【中文标题】MVC 自定义验证:比较两个日期【英文标题】:MVC custom validation: compare two dates 【发布时间】:2011-10-24 21:48:38 【问题描述】:

我创建了一个自定义 ValidationAttribute,它比较两个日期并确保第二个日期大于第一个日期:

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; 
....

客户端验证不再起作用,因为生成的 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; // 这里应该是全名???怎么样??

谢谢

【问题讨论】:

感谢您提供此代码,我已在验证中成功实现它 也感谢您的更新,感谢@counsellorben 的更新。 使用Attribute为您的课程添加后缀可能是个好主意 【参考方案1】:

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

$.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);
);

【讨论】:

【参考方案2】:

不要忘记在此代码中包含客户端。我花了好几个小时才发现它不见了!

(function ($) 

  // your code here..

)(jQuery);

【讨论】:

【参考方案3】:

只是为了修复coulorben javascript 中的一个小错误:“(params.allowequaldates)”将被解释为一个字符串(其值为“False”或“True”),但该字符串将始终被评估为真,因此总是允许相同的日期。 如果您还希望允许对象的嵌套层数超过 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);
);

【讨论】:

【参考方案4】:

在最后一个答案中,对 toLowerCase 的调用缺少一些括号,这是一个已准备好文档和 $.validator.unobtrusive...-part 的更新版本:

$(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;
        );
);

【讨论】:

以上是关于MVC 自定义验证:比较两个日期的主要内容,如果未能解决你的问题,请参考以下文章

两个日期的 Laravel 自定义验证

ASP.NET MVC2 自定义 jQuery 验证:客户端

asp.net mvc 自定义全局过滤器 验证用户是否登录

ASP.NET MVC 4 验证后自定义 jQuery 脚本无法正常工作

MVC 自定义属性验证登录

Spring 3 MVC:使用自定义验证器显示验证消息