FluentValidation - предварительная / условная проверка без дублирования кода - PullRequest
0 голосов
/ 05 сентября 2018

Я пытаюсь создать валидацию, которая может иметь две группы и блокировать вторую валидацию, если первая не удалась (она содержит много правил).

Пока что я создал частный класс BasicValidation внутри, а в 'main validator' сделайте вот что:

RuleFor(m => m).SetValidator(new BasicValidation()).DependentRules(() => {
//Complex validation
RuleFor(m => m.IdOfSthInDb)
    .MustAsync(ItemMustExists)
    .WithMessage("Item does not exist.");
});            

Это делает свое дело, но я бы хотел избежать создания этого BasicValidation для каждой модели.

Ответы [ 2 ]

0 голосов
/ 19 сентября 2018

В моем предыдущем ответе я неправильно понял вопрос. Основная цель - избежать дублирования кода в разных валидаторах. После некоторого расследования я нашел решение, которое соответствует вашим требованиям. Предположим, у вас есть модели:

public abstract class BaseModel
{
    public string BaseProperty1 { get; set; }
    public string BaseProperty2 { get; set; }
}

public class ChildModel : BaseModel
{
    public int IdOfSthInDb { get; set; }
}

Необходимо создать валидатор для базовой модели (она будет использоваться далее):

class InternalBaseModelValidator : AbstractValidator<BaseModel>
{
    public InternalBaseModelValidator()
    {
        RuleFor(x => x.BaseProperty1).NotEmpty().WithMessage("Property 1 is empty");
        RuleFor(x => x.BaseProperty2).NotEmpty().WithMessage("Property 2 is empty");
    }
}

Затем вы можете использовать новую функцию FluentValidation, которая называется PreValidate :

public class BaseModelValidator<T>: AbstractValidator<T> where T : BaseModel
{
    // necessary for reusing base rules
    private readonly InternalBaseModelValidator preValidator; 

    protected BaseModelValidator()
    {
        preValidator = new InternalBaseModelValidator();
    }

    protected override bool PreValidate(ValidationContext<T> context, ValidationResult result)
    {
        var preValidationResult = preValidator.Validate(context.InstanceToValidate);
        if (preValidationResult.IsValid)
        {
            return true;
        }

        foreach(var error in preValidationResult.Errors)
        {
            result.Errors.Add(new ValidationFailure(error.PropertyName, error.ErrorMessage, error.AttemptedValue));
        }

        return false;
    }
}

После создания валидатора для всех базовых моделей вы можете наследовать его для валидации ChildModel:

public class ChildModelValidator : BaseModelValidator<ChildModel>
{
    public ChildModelValidator() 
        : base()
    {
        RuleFor(x => x.IdOfSthInDb)
            .MustAsync(ItemMustExists)
            .WithMessage("Item does not exist.");
    }

    private Task<bool> ItemMustExists(int arg1, CancellationToken arg2)
    {
        return Task.FromResult(false); // some logic here
    }
}

Вот и все!

0 голосов
/ 15 сентября 2018

Я думаю, что шестнадцатеричный код решит вашу проблему:

var basicValidator = new BasicValidation();
RuleFor(m => m).SetValidator(basicValidator));

When(m => basicValidator.Validate(m).IsValid, () => 
{
    RuleFor(m => m.IdOfSthInDb)
        .MustAsync(ItemMustExists)
        .WithMessage("Item does not exist.");
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...