Неверные даты в DateTime ModelBinder MVC - PullRequest
0 голосов
/ 20 июня 2019

В нашем приложении мы используем слегка модифицированную версию пользовательской модели Scott Hanselman Binder, найденную здесь

Основная проблема, с которой мы столкнулись, заключалась в том, что, когда пользователь вводил недопустимый день / месяц, вместо того, чтобы терпеть неудачу и сообщать пользователю, он просто выдавал ошибку. Поэтому после модификации мы добавили сообщение об ошибке в ModelState, чтобы пользователь знал о своей ошибке.

Мой следующий вопрос: есть ли способ вернуть недопустимую строку обратно на экран просмотра, чтобы они могли увидеть свою ошибку. Основная причина, по которой мы хотели бы этого, - если пользователь редактирует существующий DateTime, он стирает все поля, а не только ошибку. Это происходит потому, что в ModelBinder в данный момент мы возвращаем null. Я предполагаю, что поскольку для viewmodel требуется DateTime, тот факт, что он недействителен, означает, что мы не можем ничего передать обратно viewmodel для его отображения.

Альтернативой может быть установка недопустимого дня или месяца на 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");
    }
...