.Net Fluent Validation устанавливает порядок выполнения

Мне нужно установить порядок выполнения для проверки, чтобы он прекратил проверку после первого сбоя.

Однако это недоступно, поэтому мне интересно, какой другой способ сделать это.

Обычно у меня было бы что-то вроде этого:

public Constructor(){

    // Simple validation
    RuleFor(x => x.Id).NotNull().NotEmpty();

    // advanced validation
    // item must exist in database
    RuleFor(x => x.Id).Must(ExistsInDatabase);

    // item must exist in database previously
    // item must be some of the allowed names -- fetched from db
    RuleFor(x => x.Id).Must(BeAReferenceInSomeTable);

    private bool ExistsInDatabase(){}

    private bool BeAReferenceInSomeTable(){}

}

Но с этим BeAReferenceInSomeTable может быть выполнен до ExistsInDatabase. Таким образом, проверка BeAReferenceInSomeTable вызовет исключение, если Id не существует в таблице, а не сбой проверки из-за проверки ExistsInDatabase.

Чтобы решить это первое, что приходит на ум, что-то вроде этого:

public Constructor(){

    CascadeMode = FluentValidation.CascadeMode.StopOnFirstFailure;

    // simple validation stays the same
    ...

    // advanced validation
    RuleFor(x => x.Id)
        .Must(ExistsInDatabase)
        .Must(BeAReferenceInSomeTable)
        .When(x => !string.IsNullOrEmpty(x.Id) &&
                    !string.IsNullOrEmpty(x.Name)
        );  
}

Но в этом случае, как мне установить правильное сообщение для проверки, поскольку сообщение должно быть предоставлено до выполнения.


person Matija K.    schedule 12.06.2014    source источник
comment
Вы можете использовать .WithMessage("your message");, чтобы добавить правильное сообщение об ошибках проверки, и это также работает с цепочкой (что вы делаете во втором примере).   -  person Moo    schedule 12.06.2014
comment
Да, но ExistsInDatabase должен вернуть: идентификатор не существует в базе данных, а BeAReference должен вернуть: идентификатор не указан в какой-либо таблице. С помощью WithMessage можно передать только статическую предопределенную строку. Но это нехорошо, так как я хочу вернуть только 1 сообщение   -  person Matija K.    schedule 12.06.2014


Ответы (1)


Попробуйте что-то вроде этого:

public Constructor(){

    // Simple validation
    RuleFor(x => x.Id).Cascade(CascadeMode.StopOnFirstFailure).NotNull().WithMessage("Must not be null");

    RuleFor(x => x.Id).NotEmpty().WithMessage("Must not be empty");


    // advanced validation
    // item must exist in database
    RuleFor(x => x.Id).Must(ExistsInDatabase).WithMessage("Must exist in database");

    // item must exist in database previously
    // item must be some of the allowed names -- fetched from db
    RuleFor(x => x.Id).Must(BeAReferenceInSomeTable).WithMessage("Must not be referenced");

    private bool ExistsInDatabase(){}

    private bool BeAReferenceInSomeTable(){}

}

И прикован к исполнению приказа:

RuleFor(x => x.Id).Cascade(CascadeMode.StopOnFirstFailure)
    .NotNull().WithMessage("Must not be null")
    .NotEmpty().WithMessage("Must not be empty")
    .Must(ExistsInDatabase).WithMessage("Must exist in database")
    .Must(BeAReferenceInSomeTable).WithMessage("Must not be referenced");
person Moo    schedule 12.06.2014
comment
Когда вы устанавливаете каскадный режим в первой строке, он используется только для этой цепочки. Таким образом, его использование без нескольких условий не имеет эффекта. Остальной код подводит меня к той же проблеме, которая открыла тему. WithMessage, который вы добавили, будет отображать правильную ошибку проверки, но проверка может выполняться не по порядку. - person Matija K.; 12.06.2014
comment
Затем используйте цепочку для достижения заказов на выполнение. - person Moo; 12.06.2014
comment
Я расширил ваш пример, чтобы получить то, что мне нужно, но это делает избыточные операции. Как вы думаете, есть лучший способ? Я отмечу ваше решение как правильное, так как оно близко (но не совсем) к тому, что мне нужно. RuleFor(x => x.Id).Must(ExistsInDatabase).WithMessage(Должен существовать в базе данных).When(x => x.Id.NotNullOrEmpty()) RuleFor(x => x.Id).Must(BeAReferenceInSomeTable) .WithMessage(На него нельзя ссылаться).When(x => x.NotNullOrEmpty() && ExistsInDatabase(x)); - person Matija K.; 12.06.2014
comment
Какие избыточные операции выполняются? - person Moo; 12.06.2014
comment
Для проверки перед проверкой выполняется BeAReferenceInSomeTable ExistsInDatabase. Для проверки ExistsInDatabase снова выполняется тот же метод. Это не проблема для этого небольшого теста, но она масштабируется в более крупных тестах. - person Matija K.; 12.06.2014
comment
Вот и все, мне даже в голову не пришло, что вы можете добавить несколько таких сообщений (я предполагал, что будет использоваться последнее). Это ответ, который я искал. Спасибо - person Matija K.; 12.06.2014