Использует FluentValidation v12 (Apache 2.0 во всех версиях), зафиксирован на
[12.0.0,13.0.0).
Установка
dotnet add package Koto.Validation
Что внутри
| Тип | Назначение |
|---|---|
KotoValidators.MustBeValueObject<T, TSource, TValueObject> | Валидирует свойство, вызывая доменную фабрику (Func<TSource, Result<TVO>>) — любой исходный тип: string, int, Guid, … |
KotoValidators.MustBeEntity<T, TElement, TEntity> | Тот же контракт для фабрик сущностей |
KotoValidators.ListMustContainNumberOfItems | Правило min/max количества для коллекций |
KotoValidators.NotEmptyWithKotoError / LengthWithKotoError | Встроенные правила с кодами Errors.General |
ValidationBehavior<TRequest, TResponse> | Pipeline-middleware — запускает все валидаторы (в т.ч. асинхронные) до хендлера |
ServiceCollectionExtensions.AddKotoValidation | Регистрирует поведение и сканирует сборки на валидаторы |
Использование
Регистрация
builder.Services.AddKotoValidation(typeof(Program).Assembly);
// Регистрирует ValidationBehavior<,> как открытый generic и сканирует IValidator<T> —
// дополнительная регистрация не нужна. Рекомендуемый порядок: Logging → Validation → Transaction.
Валидатор — один источник истины
Логика валидации живёт в доменной фабрике; валидатор только вызывает её:
public sealed class PlaceOrderValidator : AbstractValidator<PlaceOrderCommand>
{
public PlaceOrderValidator()
{
RuleFor(x => x.Email).MustBeValueObject(Email.Create); // источник — string
RuleFor(x => x.Quantity).MustBeValueObject(Quantity.Create); // источник — int, подходит любой тип
RuleFor(x => x.Items).ListMustContainNumberOfItems(1, 100);
RuleFor(x => x.CustomerId).NotEmpty();
}
}
Валидаторы индексируются по конкретному типу команды и находятся пайплайном
автоматически (диспетчер замыкает ValidationBehavior<,> на PlaceOrderCommand).
Структурированные ошибки
Каждая доменная Error передаётся как структурированное состояние — ValidationFailure.CustomState +
ErrorCode — а не как сериализованная строка сообщения. При неудаче ValidationBehavior
возвращает Result, несущий одну Error на каждое нарушение валидации, с реальными
Code, Message и Field (именем свойства). Ничего не сворачивается в одну строку; HTTP-слой
может рендерить RFC 7807 validation problem details по каждому полю (см. Koto.Api.AspNetCore).
Асинхронные правила (MustAsync, CustomAsync) полностью поддерживаются — поведение вызывает ValidateAsync.