DateTime ModelBinder MVC中的无效日期

时间:2019-06-20 15:10:06

标签: c# asp.net-mvc datetime model-binding

在我们的应用程序中,我们使用的是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");
    }

0 个答案:

没有答案