仅时间编辑器模板和验证



创建具有不显眼验证的仅时间输入字段时遇到一些问题,映射到不可为空的日期时间字段。

我正在使用数据库优先的方法。 数据库具有用于存储日期和时间的日期时间字段。 我的意思是有些日期时间有真实的日期数据和 00:00:00 的时间,而另一些则有无意义的实时日期数据。 我知道这是由于 EF5 和 C# 数据类型的限制造成的。 现在使用 EF6,但不打算更改数据库。

这是视图模型

[UIHint("Date")]
public DateTime MatchDate { get; set; }
[UIHint("Time")]
public DateTime StartTime { get; set; }

仅日期字段"匹配日期"正在工作。 它使用Date.cshtml(下图(的 EditorFor 模板。 它允许文本输入,正确附加jQuery日期选择器,并以不显眼的方式正确验证服务器端和客户端。

@model DateTime
@if (Model == DateTime.MinValue)
{
@Html.TextBox("", "", new { @class = "datepicker" })
}
else
{   
@Html.TextBox("", String.Format("{0:d/M/yyyy}", Model), new { @class = "datepicker" })
}

所以我为Time.cshtml创建了一个新的编辑器模板

@model DateTime
@if (Model == DateTime.MinValue)    
{
@Html.TextBox("", "", new { @class = "timepicker" })
}
else
{
@Html.TextBox("", String.Format("{0:h\:mm tt}", Model), new { @class = "timepicker" })
}

此时,Html 输入元素会获得不需要的data-val-date属性,从而导致不显眼的日期验证。 我发现通过添加[DataType(DataType.Time)],不再添加data-val-date。 虽然这是一件好事,但我不是,如果这完全(并且只是(数据类型属性应该做的事情。 所以这是问题的第一部分。

接下来,我为 12 小时时间格式创建了自定义验证规则(服务器和客户端(。

注解:

public class TimeTwelveAttribute : ValidationAttribute, IClientValidatable
{
private const string _ErrorMessage = "Invalid time format. Please use h:mm am/pm (TimeAttribute)";
public TimeTwelveAttribute()
{
this.ErrorMessage = _ErrorMessage;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationRule
{
ErrorMessage = _ErrorMessage,
ValidationType = "timetwelve"
};
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
DateTime time;
if (value == null || !DateTime.TryParse(value.ToString(), out time))
{
return new ValidationResult(_ErrorMessage);
}
return ValidationResult.Success;
}
}

JavaScript

$.validator.unobtrusive.adapters.addSingleVal("timetwelve");
$.validator.addMethod(
"timetwelve",
function (value, element) {
return this.optional(element) || /^((0?[1-9]|1[012])(:[0-5]d){1,2}( ?[AP]M))$/i.test(value);
},
"Invalid time format. Please use h:mm am/pm"
);

但是,将[TimeTwelve]数据批注添加到 StartTime 不起作用:

  • 服务器端验证正在进行,但它正在创建一条我无法覆盖的不同错误消息:"值'asdf'对开始时间无效。
  • 如果我在时间字段中键入"asdf",则不会弹出客户端验证消息。

我认为这是由映射到 C# 日期时间的回发值引起的。 无论哪种机制执行,都会具有更高的优先级并覆盖所有其他验证。 作为练习,我将 StartTime 重写为字符串(并更新了模板等(,果然[TimeTwelve]按预期在客户端和服务器端工作。 我觉得这是堆栈溢出的任何问题都没有涉及的方面。

因此,我问题的第二部分,鉴于我真的更喜欢在我的视图模型中使用 DateTimes,我如何才能让验证工作?

这是我能找到的最接近的问题,但它来自2013年。

首先,若要使客户端验证正常工作,请将脚本更改为

$.validator.unobtrusive.adapters.add('timetwelve', function (options) {
options.rules['timetwelve'] = {};
options.messages['timetwelve'] = options.message;
});
// no need to hard code the message - it will use the one you have defined in the validation atribute
$.validator.addMethod('timetwelve', function (value, element) {
return this.optional(element) || /^((0?[1-9]|1[012])(:[0-5]d){1,2}( ?[AP]M))$/i.test(value);
});

或者您可以使用.addBool()方法

$.validator.unobtrusive.adapters.addBool("timetwelve");

至于接收值"asdf"对开始时间无效,如果您在文本框中输入"asdf">,这是默认行为。DefaultModelBinder使用值转换器将Request中的值分析为属性类型。由于asdf不能转换为DateTime,因此添加了ModelState错误,并且没有进行进一步的验证(因为它已经无效并且没有意义(。当然,一旦客户端验证正常工作,你永远不会达到这一点(除非用户禁用了javascript或它是恶意用户(。

另请注意,您的IsValid()方法可以简单地

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
return ValidationResult.Success;
}

当您到达此处时,DefaultModelBinder已经设置了DateTime值(通过将今天的日期与表单中输入的时间相结合(,因此无需再次尝试解析它。

最新更新