Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fluent validation with dynamic message

I am trying to building custom validation with dynamic message in fluent validation library.

For example :

public class CreateProcessValidator : AbstractValidator<CreateProcessVM>
{
    public CreateProcessValidator()
    {
        RuleFor(x => x.ProcessFile).Must((x,e) => IsProcessFileValid(x.ProcessFile))).WithMessage("Parse failed with error : {0}");        
    }

    public bool IsProcessFileValid(HttpPostedFileBase file)
    {
        var errorMessage = "..."  // pass result to validaton message ?
        // logic
        return false;
    }
}

Is here any workaround how to pass validation result ?

Thanks

like image 280
Mennion Avatar asked Apr 09 '13 13:04

Mennion


2 Answers

Have you tried something like this?

public class IsProcessFileValid : PropertyValidator
{
    public IsProcessFileValid(): base("{ValidationMessage}") {}

    protected override IsValid(PropertyValidatorContext context)
    {
        if (!IsProcessFileValid1(context))
            context.MessageFormatter.AppendArgument("ValidationMessage",
                "Custom validation message #1");

        if (!IsProcessFileValid2(context))
            context.MessageFormatter.AppendArgument("ValidationMessage",
                "Custom validation message #2");

        // ...etc

        return true;
    }

    private bool IsProcessFileValid1(PropertyValidatorContext context)
    {
        // logic
        return false;
    }

    private bool IsProcessFileValid2(PropertyValidatorContext context)
    {
        // logic
        return false;
    }

    // ...etc
}

With extension method:

public static class IsProcessFileValidExtensions
{
    public static IRuleBuilderOptions<T, object> MustBeValidProcessFile<T>
        (this IRuleBuilder<T, object> ruleBuilder)
    {
        return ruleBuilder.SetValidator(new IsProcessFileValid());
    }

}

... and then use it without a custom WithMessage:

public CreateProcessValidator()
{
    RuleFor(x => x.ProcessFile).MustBeValidProcessFile();        
}

By creating a custom PropertyValidator, you can encapsulate the default validation message within that class and make it dynamic. However you must not use the .WithMessage extension when declaring the RuleFor, because that would override the default validation message which you customized directly inside the PropertyValidator.

like image 116
danludwig Avatar answered Nov 15 '22 10:11

danludwig


There's no way to do that. I would split the complex validation method you currently have into smaller methods (IsProcessFileValid1, IsProcessFileValid2, IsProcessFileValid3, ...) so that you could have more fine grained control over the error message. Also each method will be responsible for validating only once concern making them more reusable (single responsibility):

RuleFor(x => x.ProcessFile)
    .Must(IsProcessFileValid1)
    .WithMessage("Message 1")
    .Must(IsProcessFileValid2)
    .WithMessage("Message 2")
    .Must(IsProcessFileValid3)
    .WithMessage("Message 3");

Also notice how I simplified the lambda as the method could directly be passed to Must as argument.

like image 33
Darin Dimitrov Avatar answered Nov 15 '22 11:11

Darin Dimitrov