DateTime客户端验证由于格式化而失败

时间:2018-09-27 18:51:54

标签: asp.net-mvc-5 jquery-validate fluentvalidation

我正在MVC5项目中使用FluentValidation,但日期方面没有任何问题。我的目标是让GreaterThanOrEqualTo客户端验证适用于一些日期字段。我知道当前文档没有将此方法列为受支持的客户端,但是它呈现了正确的jQuery验证数据属性。

在我的模型中,我有一个属性:

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
[Display(Name = "Credit Decision Due Date")]
public DateTime? DueDate { get; set; }

在我看来,我正在使用标准的Razor语法来绘制控制组:

<div class="control-group">
    @Html.LabelFor(m => m.DueDate, new { @class = "control-label text-bold" })
    @Html.TextBoxFor(m => m.DueDate, "{0:MM/dd/yyyy}", new { @class = "span12 date-picker" })
    @Html.ValidationMessageFor(m => m.DueDate)
</div>

在我的验证器中,只有一个简单的规则:

RuleFor(m => m.DueDate).GreaterThanOrEqualTo(DateTime.Today);

注意,我也尝试过InclusiveBetween(在文档中明确列出为受支持的客户端):

RuleFor(r => r.DueDate).InclusiveBetween(DateTime.Today, DateTime.Today.AddYears(1));

使用GreaterThanOrEqualTo渲染视图的结果是:

<div class="control-group">
    <label class="control-label text-bold" for="DueDate">Credit Decision Due Date <span class="text-error required-asterisk">*</span></label>
    <input class="span12 date-picker hasDatepicker" data-val="true" data-val-range="'Credit Decision Due Date' must be greater than or equal to '9/27/2018 12:00:00 AM'." data-val-range-max="" data-val-range-min="09/27/2018 00:00:00" data-val-required="'Credit Decision Due Date' must not be empty." id="DueDate" name="DueDate" type="text" value="">
    <span class="field-validation-valid help-block" data-valmsg-for="DueDate" data-valmsg-replace="true"></span>
</div>

到目前为止,我说的一切看起来都不错,除了正在运行客户端的验证工作异常外,几乎就像它将值视为 text 而不是Date。例如,假阴性:

enter image description here

还有误报:

enter image description here

除了在选择日期后立即强制该字段进行验证之外,我没有在附加到这些字段的jQuery Datepicker中做任何事情:

$('.date-picker').datepicker({
    changeMonth: true,
    changeYear: true,
    onClose: function () {
        $(this).valid();
    }
});

默认情况下,整个应用程序使用“ en-US”语言环境。所有其他验证都有效。

我正在使用以下库版本:

  • FluentValidation 8
  • jQuery 1.11.3
  • jQuery验证1.17
  • jQuery验证不干扰3.2.10(Microsoft)

我知道我可以编写一个自定义验证器,在比较之前将输入和范围值解析为JavaScript Date对象,但是似乎应该内置一些东西,以使所有内容都将这些字符串识别为日期。

我想念什么?

1 个答案:

答案 0 :(得分:2)

问题在于range中的jquery.validate.js规则适用于数字值,如果不是数字,则进行字符串比较。

您可以通过添加自己的规则来比较日期来覆盖默认行为。在validate*脚本之后添加以下脚本,但不要在$(document).ready

内部添加以下脚本
$.validator.methods.range = function(value, element, param) {
    if ($(element).attr('data-val-date')) {
        var min = $(element).attr('data-val-range-min');
        var max = $(element).attr('data-val-range-max');
        var date = new Date(value).getTime();
        var minDate = new Date(min).getTime() || 0;
        var maxDate = new Date(max).getTime() || 8640000000000000;
        return this.optional(element) || (date >= minDate && date <= maxDate);
    }
    // use the default method
    return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
};

请注意,您的TextBoxFor()方法应生成一个data-val-date="The field Credit Decision Due Date must be a date."属性。我不确定是否只是从显示的结果html中省略了它,还是有其他一些代码省略了它。如果未生成,则需要修改if ($(element).attr('data-val-date')) {代码行,例如使用类名

if ($(element).hasClass('date-picker')) {

请注意您的

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
如果使用TextBoxFor(),则不需要

属性-仅当使用EditorFor()时才尊重这些属性,如果您使用EditorFor(),则格式字符串应为ISO格式-即The specified value does not conform to the required format yyyy-MM-dd中的DataFormatString = "{0:yyyy-MM-dd}"