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

DateTime client-side validation fails due to formatting

我在 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。例如,假阴性:

误报:

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

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

整个应用程序默认使用 "en-US" 语言环境。所有其他验证均有效。

我正在使用以下库版本:

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

我错过了什么?

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

您可以通过添加自己的规则来比较日期来覆盖默认行为。在 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')) { 行代码,可能使用 class 名称,例如

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

另请注意,您的

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]

如果使用 TextBoxFor() 则不需要属性 - 只有在使用 EditorFor() 时才会考虑这些属性,如果您确实使用 EditorFor(),则格式字符串应为 ISO 格式- 即 DataFormatString = "{0:yyyy-MM-dd}"

中所述