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:
SetValidator()