FluentValidation - How to customize the validation message in runtime

1.5k views Asked by At

In this entity:

public class Foo
{
    public Guid Id { get; set; }
    public string Type { get; set; }
    public string Name { get; set; }
}

How can I customize the validation message in runtime using another property of entity or any other string obtained from the database?

The validation message for RuleFor(foo => foo.Name) would be:

var msg = "The foo with type '" + foo.Type + "' already exists in the database with name '" + nameInDataBase + "'!"
2

There are 2 answers

2
Hugo Leonardo On BEST ANSWER

As I had a complex scenario, the solution that solved my problem was found here: Custom Validators.

Here's the validator code:

public class FooValidator : AbstractValidator<Foo>
{
    public FooValidator()
    {
        Custom(foo =>
        {
            var repo = new Repository<Foo>();
            var otherFooFromDB = repo.GetByName(foo.Name);

            if (!otherFooFromDB.Equals(foo))
            {
                return new ValidationFailure("Id", "The foo with ID'" + otherFooFromDB.Id + "' has the same name of this new item '" + foo.Id + " - " + foo.Name + "'.!");
            }
            else
            {
                return null;
            }
        });
    }
}

With this solution when validation is ok just return null. But when there is a validation error return a instance of ValidationFailure and pass in her constructor the name of the validated property and the validation message.

1
KN Coder On

Create a couple of custom validators, and define them as extension methods so you can chain them. Pass what you need to do the validation into the model. Then if you have foo.Type as a property of your model, you can display it in the message as shown below:

RuleFor(foo => foo.Name).FooTypeIsInvalidValidator().WithMessage("The foo with type: {0} is invalid!", foo => foo.Type);

or

RuleFor(foo => foo.Name).FooAlreadyExistsValidator().WithMessage("The foo with type: {0} already exists in the database with name", foo => foo.Type);