Pull to refresh

Comments 14

Выглядит сомнительно, если у нас куча моделей. Для определённого объекта придётся каждый раз создавать определённый валидатор или регистрировать тысячи их в Di.

И даже наследование не всегда поможет, если вы его вообще используете для моделей.

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

И что характерно, в этом тексте тоже ни одного такого примера не приведено, и внимание на этом не акцентировалось. Сделаем скидку на то, что это первая часть, но пока - ничего нового, ничего такого, чего принципиально не было бы сделано лет 10 назад там и сям.

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

Ну не вопрос, подождем. Просто это самое интересное, как по мне. Насколько вот такая валидация будет управляемой, понятной и т.п.

А ещё может быть такое, что валидность одной и той же модели может отличаться в зависимости от контекста.

Имхо, проще сделать приватный метод для валидации уже в самой бизнес логике и никуда его не выносить, или выносить, если класс раздулся из-за большого объёма кода.

Есть валидация на значения, а есть валидация на "существование данных". Обе эти валидации можно делать внутри валидатора, такая возможность есть. А есть второй подход, когда валидация на значения располагается внутри валидатора, а валидация на существование данных производится в бизнес логике.

Так этой библиотеки уже не менее десятка лет. Могу ошибаться, но её я впервые использовал в году 2012.

Валидаторы обычно хранятся в какой-то папке в каком-то одном месте, на один тип модели один валидатор. В библиотеке предусмотрен метод расширения для регистрации валидаторов по указанной сборке. Также предусмотрен функционал для работы с классами, которые используют наследование (переиспользование правил валидаций базового класса/интерфейса). Но про это не было упомянуто в этом обзоре, т. к. он стартовый.

Я так понимаю, что такого рода инструменты (как automapper например), очень хороши в небольших проектах. Когда у вас есть много common кода, и разные сервисы/сайты/апишки пытаются работать с одним контекстом данных, эти правила маппинга/валидации/спецификаций начинают тянуть производительность и понимание структуры кода на дно, и множат блуждающие ошибки. Например, прикрутить валидацию только для апи или сайта это одно, прикрутить тоже-самое, но в множество связанных проектов с своими доменами это боль и слезы.

Общие модели, маппинги, валидации можно выделить в NuGet пакет, дополнительно добавив туда методы расширения для удобной регистрации в DI всего сразу в отдельных проектах. Единственной проблемой от этого подхода будет то, что нужно будет обновлять пакет в каждом отдельном приложении при его изменении (не всегда правда, а только когда требуется это обновление для корректной работы приложения). Также надо правильно сортировать классы внутри проекта, чтобы было интуитивно понятно что с чем вяжется и как быстро это находить.

Последняя версия (FluentValidation 11) поддерживает следующие платформы .NET:

  • .NET Core 3.1

  • .NET 5

  • .NET 6

  • .NET 7

  • .NET 8

  • .NET Standard 2.0

Где-то я этот формальный стиль изложения уже видел... https://docs.fluentvalidation.net/en/latest/
А далее в статье идет перевод https://docs.fluentvalidation.net/en/latest/start.html.

Вы даже листинги кода взяли из официальной документации по FluentValidation. Вам не кажется, что для статьи на Хабр нужно приложить чуть больше усилий?

а вот так можно еще

using CSharpFunctionalExtensions;

public class CustomerValidator : AbstractValidator<Customer>
{
...
    private Result ValidateOrder(Order order)
    {
        return Result.Success()
            .Ensure(() => order != null, "Order cannot be null.")
            .Ensure(() => order.TotalCost > 0, "TotalCost must be greater than 0.");
    }
}

Мне кажется это плохой вариант, т. к. названия свойств указаны литералом, а не через nameof хотя бы например (после ренейма свойства будет расхождение в нейме), также тут нет поддержки локализации при том что условия валидаторов из коробки, где это реализовано уже.

Sign up to leave a comment.

Articles