Как создать собственный валидатор в ASP. NET Ядре, которое также запускается для неверного ввода? - PullRequest
1 голос
/ 15 апреля 2020

Я создал настраиваемый валидатор для поля DateTime в ASP. NET Core 3.1, как показано ниже:

[CustomDate]
public DateTime DOB { get; set; }

public class CustomDate : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        //… some logic
    }
}

Однако моя проблема заключается в том, что этот настраиваемый валидатор срабатывает только тогда, когда Я поместил значение даты в текстовое поле управления. Он не срабатывает для недопустимых вводов, например, когда я помещаю строку 'aaa' в текстовое поле.

Мой вопрос заключается в том, как заставить этот пользовательский валидатор срабатывать даже для недопустимых вводов, таких как 'string' и т. Д. c.

. Причина в том, что я хочу заменить этот пользовательский валидатор на [Required] [ReqularExpression] и др. c. Этакий «Один звонок (валидатор), чтобы управлять ими всеми». Как мне этого добиться?

1 Ответ

1 голос
/ 15 апреля 2020

TL; DR: При отправке значения, которое не может быть преобразовано в DateTime, привязка модели завершается неудачно. Поскольку с этим свойством уже связана ошибка валидации, последующая валидация, включая ваш CustomDate валидатор, не запускается. Однако ваша собственность все еще проверяется: если вы введете значение aaa, ModelState.IsValid вернет false.


Код, который вы первоначально разместили , должен работать нормально, но я подозреваю, что это не работает так, как вы ожидаете . В частности, ваша путаница, вероятно, проистекает из следующего утверждения:

"… этот пользовательский валидатор срабатывает только тогда, когда я помещаю значение даты в элемент управления текстового поля."

Это также правда! Позвольте мне пройти через процесс.

Оригинальный код

Чтобы проиллюстрировать это, я надеюсь, вы не возражаете, чтобы я воскресил ваш исходный пример кода, так как полезно иметь конкретную ссылку для отработки из.

[CustomDate]
public DateTime DOB { get; set; }

public class CustomDate : Attribute, IModelValidator
{
    public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)
    {
        if (Convert.ToDateTime(context.Model) > DateTime.Now)
            return new List<ModelValidationResult> {
                new ModelValidationResult("", "Invalid - future date")
            };
        else if (Convert.ToDateTime(context.Model) < new DateTime(1970, 1, 1))
            return new List<ModelValidationResult> {
                new ModelValidationResult("", "Invalid - date is less than 1970 year")
            };
        else
            return Enumerable.Empty<ModelValidationResult>();
    }
}

Процесс валидации

Прежде чем я пройдусь по процессу, необходимо знать четыре основных момента:

  1. Модель привязка происходит до модель проверка .
  2. При привязке модели будут возникать собственные ошибки проверки.
  3. Атрибуты проверки оцениваются только для свойств, которые остаются IsValid.
  4. Свойство ModelValidationContext.Model вводится в проверенное свойство, поэтому в этом случае значение DateTime.

Вариант использования # 1: Неверное значение

Учитывая эти соображения, вот что происходит, когда вы отправляете значение, например aaa в поле, сопоставленном с вашим проверенным свойством DOB:

  1. Модель переплета атм pts для привязки значения aaa к свойству DateTime.
  2. Связывание модели завершается неудачно, добавляя ModelError к вашему ModelStateDictionary.
  3. вашему CustomDate средству проверки никогда возникает из-за того, что поле уже не прошло проверку .

Вариант использования № 2: Отсутствует значение

Поучительно рассмотреть другой тестовый пример. Вместо ввода aaa, просто не вводите значение вообще. В этом случае процесс выглядит несколько иначе:

  1. Связыватель модели не находит значение для вашего свойства DateTime, поэтому привязка не выполняется.
  2. Свойство вашей модели инициализируется значением DateTime по умолчанию 0001-01-01 00:00:00.
  3. Ваш валидатор CustomDate срабатывает, добавляя ModelError, потому что «Недопустимая дата меньше 1970 года».

Анализ

Как вы можете видеть выше, true , что ваш CustomDate валидатор не запускается, когда отправлена ​​фиктивная дата. Но это не означает , что проверка не происходит. Вместо этого проверка уже произошла и не удалась. Если вы введете правильную дату (или вообще не введете дату), то ошибка привязки модели не произойдет, и ваш CustomDate валидатор будет выполнен, как и ожидалось.

Повторное рассмотрение вашего вопроса

"Как заставить этот пользовательский валидатор запускаться даже для недопустимых вводов, таких как 'string' и c."

В конечном счете, я не ответил на этот вопрос. Но я думаю мой ответ объяснит почему происходит и почему ваш ввод все еще проходит проверку несмотря на это. Имейте в виду, что даже если ваш CustomDate валидатор сработал , он будет работать так же, как если бы вы вообще не отправляли значение, поскольку значение context.Model по умолчанию было бы 0001-01-01 00:00:00 , Основное различие заключается в том, что вы не получаете одно и то же сообщение об ошибке, поскольку ошибка исходит из другого источника.

Принудительная проверка

Я не рекомендую это, но если вы действительно хотел, чтобы ваш CustomDate валидатор сработал, вместо этого вы можете применить его к свойству string. В этом случае привязка модели не произойдет, и ваш валидатор CustomDate все равно будет вызван. Если вы выполните это, вам нужно будет провести дополнительную проверку, чтобы убедиться, что дата в правильном формате (например, путем выгрузки или обработки InvalidFormatException с). Но, конечно, ваша дата будет сохранена как string, что, вероятно, не то, что вы хотите.

Рекомендации по коду

Это немного выходит за рамки вашего исходного вопроса , но пока я здесь, я бы порекомендовал следующее:

  1. Вам не нужно будет делать Convert.ToDateTime() в своем валидаторе; ваше context.Model поле уже a DateTime. Вам просто нужно привести его обратно к объекту DateTime (например, (DateTime)context.Model), чтобы ваш код знал это.
  2. Как минимум, вам следует рассмотреть возможность использования <input type="date" /> ( reference ) ), который в большинстве браузеров ограничивает ввод правильной датой, а также предоставляет базовый c указатель даты.
  3. В качестве альтернативы, существует ряд более сложных элементов управления датой / временем, написанных в JavaScript, которые Вы можете рассмотреть возможность внедрения, если вам требуется больше контроля над презентацией и проверкой на стороне клиента.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...