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