
← Предыдущая часть | Следующая часть →
Библиотеку FluentValidation можно использовать с любой библиотекой внедрения зависимостей. В этой части будут примеры на библиотеке Microsoft.Extensions.DependencyInjection. У нас есть следующие валидаторы:
// Модель адреса public class Address { ... } // Валидатор для модели адреса public class AddressValidator : AbstractValidator<Address> { ... } // Модель заказа public class Order { ... } // Валидатор для модели заказа public class OrderValidator : AbstractValidator<Order> { ... } // Модель клиента public class Customer { // Имя public string? Forename { get; set; } // Адрес public Address? Address { get; set; } } // Валидатор для модели клиента public class CustomerValidator : AbstractValidator<Customer> { // Получаем через конструктор валиадтор для модели адреса (AddressValidator) public CustomerValidator(IValidator<Address> addressValidator) { RuleFor(customer => customer.Forename) .NotNull(); // Применяем полученный валидатор RuleFor(customer => customer.Address) .SetValidator(addressValidator); } }
И следующий сервис:
// Сервис клиента public class CustomerService { private readonly IValidator<Customer> _validator; // Получаем CustomerValidator через конструктор public CustomerService(IValidator<Customer> validator) { _validator = validator; } // Валидируем, возвращаем результат валидации (true/false) public bool Validate(Customer customer) { var result = _validator.Validate(customer); return result.IsValid; } }
Ручная регистрация
Валидаторы можно регистрировать через интерфейс IValidator<T> где T тип валидируемой модели:
using Microsoft.Extensions.DependencyInjection; static void Main(string[] args) { var services = new ServiceCollection(); services.AddScoped<CustomerService>(); // Регистрируем валидаторы services.AddScoped<IValidator<Customer>, CustomerValidator>(); services.AddScoped<IValidator<Address>, AddressValidator>(); // AddScoped можно заменить на AddTransient, AddSingleton по необходимости var provider = services.BuildServiceProvider(); // Создаём модель клиента var customer = new Customer { }; // Получаем CustomerService из DI контейнера var customerService = provider.GetRequiredService<CustomerService>(); // Валидируем модель клиента, получаем результат валидации var isValid = customerService.Validate(customer); }
Автоматическая регистрация
Для автоматической регистрации валидаторов, нужно «подтянуть» пакет FluentValidation.DependencyInjectionExtensions. В нём предусмотрено 4 публичных метода расширения:
Метод расширения: AddValidatorsFromAssemblyContaining<T>Описание: Зарегистрировать все валидаторы, которые есть в сборке T типа:
static void Main(string[] args) { var services = new ServiceCollection(); // Регистрируем все валидаторы, которые есть в сборке типа CustomerValidator // Указываем через параметры типа services.AddValidatorsFromAssemblyContaining<CustomerValidator>(); var provider = services.BuildServiceProvider(); // ... }
Метод расширения: AddValidatorsFromAssemblyContaining(Type)
Описание: Зарегистрировать все валидаторы, которые есть в сборке Type типа:
static void Main(string[] args) { var services = new ServiceCollection(); // Регистрируем все валидаторы, которые есть в сборке типа CustomerValidator // Работает аналогично примеру выше, только указываем через объект типа Type, // а не через параметры типа services.AddValidatorsFromAssemblyContaining(typeof(CustomerValidator)); var provider = services.BuildServiceProvider(); // ... }
Метод расширения: AddValidatorsFromAssembly(Assembly)
Описание: Зарегистировать все валидаторы, которые есть в указанной сборке Assembly:
static void Main(string[] args) { var services = new ServiceCollection(); // Регистрируем все валидаторы, которые есть в сборке // под названием FluentValidationTests services.AddValidatorsFromAssembly(Assembly.Load("FluentValidationTests")); var provider = services.BuildServiceProvider(); // ... }
Метод расширения: AddValidatorsFromAssemblies(IEnumerable<Assembly>)
Описание: Зарегистрировать все валидаторы, которые есть в указанных сборках Assembly:
static void Main(string[] args) { var services = new ServiceCollection(); var assemblies = new[] { "FluentValidationTests", "SomeAnotherAssembly" }.Select(Assembly.Load); // Регистрируем все валидаторы, которые есть в сборках под названиями: // FluentValidationTests и SomeAnotherAssembly services.AddValidatorsFromAssemblies(assemblies); var provider = services.BuildServiceProvider(); // ... }
Жизненный цикл валидаторов при автоматической регистрации
Вы можете опционально настраивать жизненный цикл валидаторов, с помощью параметра lifetime и значения перечисления ServiceLifetime (по умолчанию указано ServiceLifetime.Scoped):
static void Main(string[] args) { var services = new ServiceCollection(); // Указываем для всех валидаторов жизненный цикл Scoped (новый объект на указанную область) services.AddValidatorsFromAssemblyContaining<CustomerValidator>(lifetime: ServiceLifetime.Scoped); var provider = services.BuildServiceProvider(); // ... }
Фильтрация валидаторов при автоматической регистрации
Вы можете опционально указать предикат, по которому будет осуществляться проверка, стоит ли регистрировать очередной валидатор в DI контейнер или же нет. Код из примера ниже показывает, как исключить валидаторы AddressValidator и OrderValidator, при этом зарегистировав все остальные:
static void Main(string[] args) { var services = new ServiceCollection(); var excludeValidators = new[] { typeof(AddressValidator), typeof(OrderValidator), }; // Все валидаторы будут зарегистрированы, кроме тех, которые есть в массиве excludeValidators services.AddValidatorsFromAssemblyContaining<CustomerValidator>(filter: filter => !excludeValidators.Contains(filter.ValidatorType)); var provider = services.BuildServiceProvider(); // ... }
Такой же пример, только исключаем через интерфейс IValidator<T>:
static void Main(string[] args) { var services = new ServiceCollection(); var excludeValidators = new[] { typeof(IValidator<Address>), typeof(IValidator<Order>), }; // Все валидаторы будут зарегистрированы, кроме тех, которые есть в массиве excludeValidators services.AddValidatorsFromAssemblyContaining<CustomerValidator>(filter: filter => !excludeValidators.Contains(filter.InterfaceType)); var provider = services.BuildServiceProvider(); // ... }
Регистрация internal валидаторов при автоматической регистрации
Вы можете опционально указать, стоит ли регистрировать валидаторы, у которых указан модификатор доступа internal, через параметр includeInternalTypes:
static void Main(string[] args) { var services = new ServiceCollection(); // Регистрируем все валидаторы, включая определённые с модификатором доступа // internal services.AddValidatorsFromAssemblyContaining<CustomerValidator>(includeInternalTypes: true); var provider = services.BuildServiceProvider(); // ... }
А есть ли такие же параметры у других методов расширений?
Да, есть. У каждого вышеперечисленного метода расширения есть опциональные параметры lifetime, filter, includeInternalTypes:
lifetime по умолчанию равен ServiceLifetime.Scoped
filter по умолчанию равен null
includeInternalTypes по умолчанию равен false
