Search
Write a publication
Pull to refresh

Comments 24

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

Первый: чем FluentValidator лучше, чем валидация на основе атрибутов DataAnnotations?
Второй: вы знаете, когда выполняется валидатор, определенный атрибутом на классе, и почему в нем не следует задавать правила для отдельных свойств?
1) всё в одном месте; сложный код проверки тоже в одном месте; делает «более чистые» классы модели (не загрязненные атрибутами); проще для юнит тестирования; поддержка не только asp.net mvc

наверно это не всё…
«делает «более чистые» классы модели (не загрязненные атрибутами);»
Во-первых, атрибут все равно есть. Во-вторых, почему валидационный атрибут загрязняет модель, если он описывает ее бизнес-ограничения?

«проще для юнит тестирования»
Что именно вы хотите протестировать?

«поддержка не только asp.net mvc»
DataAnnotations тоже поддерживаются не только в asp.net mvc.
можно и без атрибута. Модель может быть использована не один раз и в разных бизнес сценариях — откуда может быть разные правила валидации её.

Протестировать валидацию собственно. Пример из офиц. доки.

«можно и без атрибута. Модель может быть использована не один раз и в разных бизнес сценариях — откуда может быть разные правила валидации её.»
Вот только в посте об этом ни слова вообще. Спасибо.

«Протестировать валидацию собственно. Пример из офиц. доки.»
Ну, эта проблема распадается на две.

Первое — тестирование кастомной валидации. Это в DataAnnotations делается так же, потому что это отдельный атрибут. Поставляемую «из коробки» валидацию не тестируют, это бессмысленно.

И второе — это тестирование того, привязана ли нужная валидация к конкретному юз-кейсу. В этом случае тестирование для FV и для DA одинаковое — мы вызываем юз-кейс и смотрим, вернул ли он нам ошибки.
В статье я только поверхностно коснулся того, что такое FV.

По поводу тестирования атрибутов — это отельный вопрос. Мне нужно было для валидации получать данные из БД. Замокать логику доступа к данным в атрибуте в юнит тестах довольно сложно, потому что это метаданные класса, нельзя использовать наследование или заменить атрибут во время выполнения. С FV это делается очень просто.
«В статье я только поверхностно коснулся того, что такое FV.»
Именно поэтому я и спросил, чем он лучше DataAnnotations.

«Мне нужно было для валидации получать данные из БД. Замокать логику доступа к данным в атрибуте в юнит тестах довольно сложно, потому что это метаданные класса, нельзя использовать наследование или заменить атрибут во время выполнения. С FV это делается очень просто. „
В вашем примере тоже атрибут. К нему применимы все ограничения по тестированию, которые применимы к DataAnnotations. Ну и нет ничего сложного замокать логику доступа к данным в атрибуте, поскольку атрибут — это такой же код, как и все остальное, вынесите данные в сервис и обратитесь к нему через сервис-локатор.
вынесите данные в сервис и обратитесь к нему через сервис-локатор


Я почитал немного про сервис-локаторы. Можно небольшой пример как передать атрибуту именно локатор, у которого он может получить сервис?

Я вижу проблему в том, что при каждом обращении к атрибуту объекта через рефлексию создается новый экземпляр атрибута, поэтому вариант с установкой локатора через сеттер свойства не подходит.

С другой стороны задать конкретный локатор в конструкторе мы не может т.к. там должна быть либо константа времени компиляции либо тип.

Я что-то упускаю или не правильно понял реализацию сервис-локатора?
«Я почитал немного про сервис-локаторы. Можно небольшой пример как передать атрибуту именно локатор, у которого он может получить сервис?»
Эээ… сервис-локатор никуда не передается, он глобальный. В этом, собственно, весь пойнт.

Какое-то статическое свойство какого-то класса? А как его в таком случае фейкать при тестировании?

Чуток погуглив нашел вопрос на stackoverflow. Видимо, фейкать нужно как раз свойство DependencyInjector.Current.

Да, теперь понятнее, а то не складывалась картинка, не хватало пазла, спасибо =)
«А как его в таком случае фейкать при тестировании?»
Его (свойство) не фейкают, просто в сетапе пишут туда нужный резолвер, вот и все.
Да, я это и имел в виду, неправильно выразился.
> Модель может быть использована не один раз и в разных бизнес сценариях

Можно пример? Если это модель из нескольких свойств, то проще создать заново. А если что-то большое, то это как правило специфическое и повтороное использование без изменений сомнительно.

В этом контексте разделение валидации и модели (а валидация по сути часть бизнес-логики), мне кажется сомнительным удовольствием. Исключение — специфические для UI (или других, кроме BL, слоев) атрибуты.
Об исключениях и идет речь.
Как бы вы стали делать валидацию такого «сценария» (да и чтобы писанины было поменьше рутинной): два юзера: простой и супер. Что-то покупают, указывая количество. Первому можно «до 10 штук» купить, второму «до 20 штук»?
Своим атрибутом, указанным в моделе.

Я под исключениями имелл виду например атрибут блокировки HTML тегов для текстовых полей и т.д.
Если в модели для каждого свойства заданы несколько атрибутов для валидации (обязательность, длина, регулярное выражение, какой-то кастомный, например) — модель превращается у «ужасного монстра». А если добавить еще и локализацию — то сложно будет разглядеть свойства под навешанными атрибутами.

При FV добавляется всего один атрибут класса и вся логика находится в нем. Модель становится намного легче и понятнее.
«Если в модели для каждого свойства заданы несколько атрибутов для валидации (обязательность, длина, регулярное выражение, какой-то кастомный, например) — модель превращается у «ужасного монстра».»
Зато при взгляде на модель сразу видны наложенные на нее бизнес-правила.

«Модель становится намного легче и понятнее. „
Легче — да. Понятнее? Нет, потому что мы перестаем видеть бизнес-правила.
Понятнее? Нет, потому что мы перестаем видеть бизнес-правила.

В студии довольно просто перейти к определению класса атрибута и посмотреть бизнес-правила. Тут, наверное, кому как удобнее. Мне было сложно визуально выделять атрибуты валидиции, особенно условные с зависимостями на другие свойства. Они было громоздкие.

Для простых правил DA мне тоже отлично подходит.
«В студии довольно просто перейти к определению класса атрибута и посмотреть бизнес-правила.»
Когда вы смотрите на обращение к свойству объекта где-то по месту его использования? Надо сначала перейти на определение класса (что само по себе не одно действие), а потом на определение атрибута. А для конкретных атрибутов на свойстве достаточно всплывающей подсказки, показывающей атрибуты.
когда выполняется валидатор, определенный атрибутом на классе

Для MVC при байндинге модели, так же как и DA.

почему в нем не следует задавать правила для отдельных свойств

Не совсем понял вопрос. Но столкнулся с ситацией когда определен DA атрибут [Required] и FV NotEmpty() при построении представления происходило исключение связанное с тем, что для свойства одно и тоже правило было задано несколько раз.

А, все, я посмотрел в документацию. Вы пропустили один маааааленький момент: чтобы все это работало, надо еще не забыть зарегистрировать собственную фабрику валидаторов FV: FluentValidationModelValidatorProvider.Configure();

Вопрос про «время срабатывания» снимается (хотя я все-таки рекомендую посмотреть, как DA обрабатывает такие ситуации, это… поучительно).
зарегистрировать собственную фабрику валидаторов FV: FluentValidationModelValidatorProvider.Configure();

Упустил этот момент, спасибо.

рекомендую посмотреть, как DA обрабатывает такие ситуации

Не до конца понял какие именно ситуации. Можно ссылочку где это можно посмотреть?
«Не до конца понял какие именно ситуации.»
Когда у вас валидатор определен на классе, а не на свойстве (и вы используете дефолтную фабрику валидации).

Ссылки по этому поводу нет, я просто читал код дефолтного валидатора.
Sign up to leave a comment.

Articles