Comments 4
Скажите, а вот эти правила RuleFor они проверяются в том же порядке, что и объявлены в конструкторе или нет? Мне вот нужно было, чтобы 1 из правил обязательно первым проверилось.
А если есть асинхронные проверки MustAcync?
Я так и не понял этот момент, пока доки смотрел. Для хоть какой-то гарантии последовательности я использовал DependentRules(). Нужно было быстро решение выкатить. Но вот что-то до сих пор сомнения терзают, нужно ли было так заморачиваться.
DependentRules()
как один из способов, но есть другой, который больше подойдёт в вашем случае, использование метода Cascade(CascadeMode.Stop)
:
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
RuleFor(customer => customer.Forename)
.Cascade(CascadeMode.Stop) // Вызов здесь
.NotNull()
.MustAsync(async (forename, token) =>
{
await Task.Delay(TimeSpan.FromSeconds(3), token);
return forename!.Count() > 4;
});
}
}
Если NotNull
зафейлится, MustAsync
не будет выполнен (с последующими валидаторами в правиле аналогичное поведение).
Если надо много раз дублировать метод Cascade
на каждый вызов метода RuleFor
, то есть более сокращённая запись, присвоение RuleLevelCascadeMode = CascadeMode.Stop
:
public class CustomerValidator : AbstractValidator<Customer>
{
public CustomerValidator()
{
// Присвоение здесь, будет работать для всех правил в CustomerValidator
RuleLevelCascadeMode = CascadeMode.Stop;
RuleFor(customer => customer.Forename)
.NotNull()
.MustAsync(async (forename, token) =>
{
await Task.Delay(TimeSpan.FromSeconds(3), token);
return forename!.Count() > 4;
});
}
}
Есть ещё что сказать, но это всё тема отдельной части статьи. Если в документации искать, то оно тут: https://docs.fluentvalidation.net/en/latest/cascade.html
RuleLevelCascadeMode это не совсем про то, про что я писал. Это работает для варианта, когда есть вот такая последовательная проверка:
RuleFor(x => x.Surname).NotNull().NotEqual("foo");
Т.е. сперва проверяем пропс на null, потом его же на не совпадение или ещё что-то.
А если есть вот такой набор правил:
RuleFor().MastAsync();
RuleFor(r => r.Prop1).NotEmpty();
RuleFor(r => r.Prop2).NotEmpty();
...
RuleFor(r => r.PropN).NotEmpty();
То гарантировать, что первое правило точно будет проверено до всех остальных, можно через DependentRules(). RuleLevelCascadeMode тут не подойдёт, как я понял.
И всё таки, точно ли порядок проверки этих правил он НЕ такой же, как его описал программист. Как эти правила проверятся: последовательно, параллельно или в случайном порядке? Или ещё как-то?
Про порядок выполнения правил из документации:
Из раздела Dependent Rules:
By default, all rules in FluentValidation are separate and cannot influence one another. This is intentional and necessary for asynchronous validation to work. However, there may be some cases where you want to ensure that some rules are only executed after another has completed.
Тоесть тут про то, что оно может выполниться как в том же порядке в котором описаны, так и в любом другом, гарантий никаких нет. А если нужны гарантии, нужно использовать DependentRules
метод.
Про порядок выполнения валидаторов из документации:
Из раздела Setting the Cascade mode:
public class PersonValidator : AbstractValidator<Person> {
public PersonValidator() {
RuleFor(x => x.Surname).NotNull().NotEqual("foo");
}
}
This will first check whether the Surname property is not null and then will check if it’s not equal to the string “foo”. If the first validator (
NotNull
) fails, then by default, the call toNotEqual
will still be invoked.
Валидаторы вызываются в том порядке в котором определены, не важно отработал предыдущий валидатор или нет, вызывается каждый.
Ничего не мешает сделать такую запись (MustAsync
+ DependentRules
):
RuleFor(customer => customer.Address.Actual)
.MustAsync(async (actual, token) =>
{
// Какая-то долгая асинхронная операция
})
.DependentRules(() =>
{
// Какой-то RuleFor на какое-то свойство
});
Асинхронность это про неблокирование главного потока, поэтому это будет работать корректно.
Обзор библиотеки FluentValidation. Часть 4. Сообщения об ошибках. Локализация