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>();
}
}
Процесс валидации
Прежде чем я пройдусь по процессу, необходимо знать четыре основных момента:
- Модель привязка происходит до модель проверка .
- При привязке модели будут возникать собственные ошибки проверки.
- Атрибуты проверки оцениваются только для свойств, которые остаются
IsValid
. - Свойство
ModelValidationContext.Model
вводится в проверенное свойство, поэтому в этом случае значение DateTime
.
Вариант использования # 1: Неверное значение
Учитывая эти соображения, вот что происходит, когда вы отправляете значение, например aaa
в поле, сопоставленном с вашим проверенным свойством DOB
:
- Модель переплета атм pts для привязки значения
aaa
к свойству DateTime
. - Связывание модели завершается неудачно, добавляя
ModelError
к вашему ModelStateDictionary
. - вашему
CustomDate
средству проверки никогда возникает из-за того, что поле уже не прошло проверку .
Вариант использования № 2: Отсутствует значение
Поучительно рассмотреть другой тестовый пример. Вместо ввода aaa
, просто не вводите значение вообще. В этом случае процесс выглядит несколько иначе:
- Связыватель модели не находит значение для вашего свойства
DateTime
, поэтому привязка не выполняется. - Свойство вашей модели инициализируется значением
DateTime
по умолчанию 0001-01-01 00:00:00
. - Ваш валидатор
CustomDate
срабатывает, добавляя ModelError
, потому что «Недопустимая дата меньше 1970 года».
Анализ
Как вы можете видеть выше, true , что ваш CustomDate
валидатор не запускается, когда отправлена фиктивная дата. Но это не означает , что проверка не происходит. Вместо этого проверка уже произошла и не удалась. Если вы введете правильную дату (или вообще не введете дату), то ошибка привязки модели не произойдет, и ваш CustomDate
валидатор будет выполнен, как и ожидалось.
Повторное рассмотрение вашего вопроса
"Как заставить этот пользовательский валидатор запускаться даже для недопустимых вводов, таких как 'string' и c."
В конечном счете, я не ответил на этот вопрос. Но я думаю мой ответ объяснит почему происходит и почему ваш ввод все еще проходит проверку несмотря на это. Имейте в виду, что даже если ваш CustomDate
валидатор сработал , он будет работать так же, как если бы вы вообще не отправляли значение, поскольку значение context.Model
по умолчанию было бы 0001-01-01 00:00:00
, Основное различие заключается в том, что вы не получаете одно и то же сообщение об ошибке, поскольку ошибка исходит из другого источника.
Принудительная проверка
Я не рекомендую это, но если вы действительно хотел, чтобы ваш CustomDate
валидатор сработал, вместо этого вы можете применить его к свойству string
. В этом случае привязка модели не произойдет, и ваш валидатор CustomDate
все равно будет вызван. Если вы выполните это, вам нужно будет провести дополнительную проверку, чтобы убедиться, что дата в правильном формате (например, путем выгрузки или обработки InvalidFormatException
с). Но, конечно, ваша дата будет сохранена как string
, что, вероятно, не то, что вы хотите.
Рекомендации по коду
Это немного выходит за рамки вашего исходного вопроса , но пока я здесь, я бы порекомендовал следующее:
- Вам не нужно будет делать
Convert.ToDateTime()
в своем валидаторе; ваше context.Model
поле уже a DateTime
. Вам просто нужно привести его обратно к объекту DateTime
(например, (DateTime)context.Model
), чтобы ваш код знал это. - Как минимум, вам следует рассмотреть возможность использования
<input type="date" />
( reference ) ), который в большинстве браузеров ограничивает ввод правильной датой, а также предоставляет базовый c указатель даты. - В качестве альтернативы, существует ряд более сложных элементов управления датой / временем, написанных в JavaScript, которые Вы можете рассмотреть возможность внедрения, если вам требуется больше контроля над презентацией и проверкой на стороне клиента.