在使用不显眼的验证创建仅限时间的输入字段时遇到问题,映射到不可为空的DateTime字段。
我正在使用数据库优先方法。数据库具有用于存储日期和时间的日期时间字段。我的意思是一些日期时间有实际日期数据,00:00:00时间,而其他日期数据有实时无意义日期数据。我理解这是由于EF5和C#数据类型的限制。现在使用EF6,但并不是特意打算更改数据库。
这是视图模型
[UIHint("Date")]
public DateTime MatchDate { get; set; }
[UIHint("Time")]
public DateTime StartTime { get; set; }
仅限日期字段MatchDate正在运行。它使用EditorFor模板Date.cshtml
(下面)。它允许文本输入,正确附加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无效:
我收集这是由于回发值映射到C#DateTimes引起的。无论什么机制都需要更高的优先级并覆盖所有其他验证。作为练习,我将StartTime重新编写为字符串(并更新了模板等),确保[TimeTwelve]
正常工作,客户端和服务器端按预期工作。我觉得这个方面在stackoverflow上的任何相关问题都没有涉及。
所以我的问题的第二部分,鉴于我真的更喜欢在我的视图模型中使用DateTimes,我如何才能使验证工作?
This是我能找到的最接近的问题,但是从2013年开始。
答案 0 :(得分:2)
首先,要使客户端验证工作,请将脚本更改为
$.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");
至于接收值&#39; asdf&#39;如果您输入&#34; asdf&#34;对于开始时间无效在文本框中,这是默认行为。 DefaultModelBinder
使用ValueConverters将Request
中的值解析为属性类型。由于asdf
无法转换为DateTime
,因此会添加ModelState
错误,并且不会进行进一步的验证(因为它已经无效并且没有任何意义)。当然,一旦客户端验证工作正常,您无论如何都不会达到这一点(除非用户已禁用javascript或其恶意用户)。
另请注意,您的IsValid()
方法可以只是
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
return ValidationResult.Success;
}
当您到达此处时,DefaultModelBinder
已设置DateTime
值(通过将今天的日期与表单中输入的时间相结合),因此无需尝试再次解析它。