在我们的应用程序中,我们使用的是Scott Hanselman的Custom Model Binder的略微修改版本,发现here
我们遇到的主要问题是,当用户输入无效的日/月时,与其优雅地失败并向用户报告,不如抛出错误。因此,在修改后,我们向ModelState添加了一条错误消息,以便用户知道他们的错误。
我的后续问题是是否有一种方法可以将无效字符串传递回视图屏幕,以便他们可以看到其错误。我们希望这样做的主要原因是,如果用户编辑现有的DateTime,它将擦除所有字段,而不仅仅是错误。之所以发生这种情况,是因为目前在ModelBinder中,我们返回null。我的假设是,由于视图模型需要DateTime,因此它是无效的,这意味着我们无法将任何内容传递回视图模型以进行显示。
另一种选择是将无效的日期或月份设置为1,以保持他们输入的其他信息。
如果有人有什么想法,更好的主意或解决方案,那就太好了。
ModelBinder代码。
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var month = bindingContext.GetValue<int>(components.Month);
var day = bindingContext.GetValue<int>(components.Day);
if ((month.HasValue && (month.Value > 12 || month.Value < 1)) || (day.HasValue && (day.Value > 31 || day.Value < 1)))
{
bindingContext.ModelState.AddModelError(bindingContext.ModelName,
"Please ensure that the Month and Date are valid.");
return null;
}
//Maybe we're lucky and they just want a DateTime the regular way.
var dateTimeAttempt = bindingContext.GetValue<DateTime>("DateTime");
if (dateTimeAttempt != null)
{
return dateTimeAttempt.Value;
}
//Did they want the Date *and* Time?
var dateAttempt = bindingContext.GetValue<DateTime>(components.Date);
var timeAttempt = bindingContext.GetValue<DateTime>(components.Time);
//Maybe they wanted the Time via parts
if (components.HourMinuteSecondSet)
{
var hour = bindingContext.GetValue<int>(components.Hour);
var minute = bindingContext.GetValue<int>(components.Minute);
var second = bindingContext.GetValue<int>(components.Second);
if (hour.HasValue && minute.HasValue && !second.HasValue)
{
//We don't care about seconds
second = 0;
}
if (hour.HasValue && minute.HasValue)
{
timeAttempt = new DateTime(
DateTime.MinValue.Year, DateTime.MinValue.Month, DateTime.MinValue.Day,
hour.Value,
minute.Value,
second.Value);
}
}
//Maybe they wanted the Date via parts
if (components.MonthDayYearSet)
{
var year = bindingContext.GetValue<int>(components.Year);
month = bindingContext.GetValue<int>(components.Month);
day = bindingContext.GetValue<int>(components.Day);
if (year.HasValue && month.HasValue && day.HasValue)
{
if (month.Value > 12 || month.Value < 1 || day.Value > 31 || day.Value < 1)
{
bindingContext.ModelState.AddModelError(bindingContext.ModelName,
new ArgumentOutOfRangeException(nameof(bindingContext),
"Please ensure that the Month and Date are in the correct textbox."));
return dateAttempt;
}
dateAttempt = new DateTime(
year.Value,
month.Value,
day.Value,
DateTime.MinValue.Hour, DateTime.MinValue.Minute, DateTime.MinValue.Second);
}
}
//If we got both parts, assemble them!
if (dateAttempt != null && timeAttempt != null)
{
return new DateTime(dateAttempt.Value.Year,
dateAttempt.Value.Month,
dateAttempt.Value.Day,
timeAttempt.Value.Hour,
timeAttempt.Value.Minute,
timeAttempt.Value.Second);
}
//Only got one half? Return as much as we have!
return dateAttempt ?? timeAttempt;
}
控制器
[HttpPost]
public ActionResult Test(TestModel modelTest)
{
var val = modelTest.dob;
if (!ModelState.IsValid)
return View("Browsers", modelTest);
return RedirectPermanent(AppLocator.GetAppBaseUrl(AppType.Net) + "/Account/Account/AccountHome");
}