简体   繁体   中英

Access Parent DisplayName in CustomValidator in FluentValidation

I have a ViewModel ( BarViewModel ) with several properties ( Owner , Customer ) of type Person . I want one custom validator ( PersonValidator ) to validate those properties. I do want to access the DisplayAttribute of those Person properties within the custom validator. But I get null as a result for the PropertyName if I use the custom validator, but not if I use the validation directly within the BarViewModelValidator . How can I access the DisplayAttribute within my custom validator?

Result for the errors variable:

" must be over 18 years. (Child Validator)"

"A Customer must be over 18 years. (Parent Validator)"

[TestFixture]
public class BarViewModelTests
{
    public class BarViewModel
    {
        [Display(Name = "Owner of bar")]
        public Person Owner { get; set; } = new Person();

        [Display(Name = "A Customer")]
        public Person Customer { get; set; } = new Person();
    }

    public class Person
    {
        public int Age { get; set; }
    }

    public class PersonValidator : AbstractValidator<Person>
    {
        public PersonValidator()
        {
            RuleFor(p => p).Custom((_, context) =>
            {
                if ((context.InstanceToValidate as Person)!.Age < 18)
                {
                    context.AddFailure($"{context.PropertyName}.{nameof(Person.Age)}", $"{context.DisplayName} must be over 18 years. (Child Validator)");
                }
            });
        }
    }

    public class BarViewModelValidator : AbstractValidator<BarViewModel>
    {
        public BarViewModelValidator()
        {
            RuleFor(p => p.Owner).SetValidator(new PersonValidator());
            RuleFor(p => p.Customer).SetValidator(new PersonValidator());

            RuleFor(p => p.Customer).Custom((_, context) =>
            {
                if ((context.InstanceToValidate as BarViewModel)!.Customer.Age < 18)
                {
                    context.AddFailure($"{context.PropertyName}.{nameof(Person.Age)}", $"{context.DisplayName} must be over 18 years. (Parent Validator)");
                }
            });
        }
    }

    private BarViewModelValidator _validator;

    [SetUp]
    public void Setup()
    {
        _validator = new BarViewModelValidator();
    }

    [Test]
    public void Should_have_proper_display_name()
    {
        var model = new BarViewModel
        {
            Owner = new Person
            {
                Age = 20
            },
            Customer = new Person
            {
                Age = 15
            }
        };

        var errors = _validator.TestValidate(model).Errors;
    }
}

I do know that this would work, but that's not how I want to solve the problem:

public class PersonValidator : AbstractValidator<Person>
    {
        public PersonValidator(string displayName)
        {
            RuleFor(p => p).Custom((_, context) =>
            {
                if ((context.InstanceToValidate as Person)!.Age < 18)
                {
                    context.AddFailure($"{context.PropertyName}.{nameof(Person.Age)}", $"{displayName} must be over 18 years. (Child Validator)");
                }
            });
        }
    }

    public class BarViewModelValidator : AbstractValidator<BarViewModel>
    {
        public BarViewModelValidator()
        {
            RuleFor(p => p.Owner).SetValidator(new PersonValidator("Owner of bar"));
            RuleFor(p => p.Customer).SetValidator(new PersonValidator("A Customer"));
        }
    }

Child validators do not know about the parent validator, so they can't access the parent property name like this. So there are three options left:

  • to explicitly pass it in via the constructor and use SetValidator()
  • to define the child rules directly inside the parent validator
  • to define an extension instead and use it similar to the child validator

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM