'FluentValidation message for nested properties
I have a class with a complex property:
public class A
{
public B Prop { get; set; }
}
public class B
{
public int Id { get; set; }
}
I've added a validator:
public class AValidator : AbstractValidator<A>
{
public AValidator()
{
RuleFor(x => x.A.Id)
.NotEmpty()
.WithMessage("Please ensure you have selected the A object");
}
}
But during client-side validation for A.Id I still have a default validation message: 'Id' must not be empty. How can I change it to my string from the validator?
Solution 1:[1]
You can achieve this by using custom validator for nested object:
public class AValidator : AbstractValidator<A>
{
public AValidator()
{
RuleFor(x => x.B).NotNull().SetValidator(new BValidator());
}
class BValidator : AbstractValidator<B>
{
public BValidator()
{
RuleFor(x => x.Id).NotEmpty().WithMessage("Please ensure you have selected the B object");
}
}
}
public class A
{
public B B { get; set; }
}
public class B
{
public int Id { get; set; }
}
Solution 2:[2]
There is an alternative option here. When configuring FluentValidation in your Startup class you can set the following configuration.ImplicitlyValidateChildProperties = true;
So the full code might look something like this
services
.AddMvc()
.AddFluentValidation(configuration =>
{
...
configuration.ImplicitlyValidateChildProperties = true;
...
})
So you would still have two validators one for class A and one for class B, then class B would be validated.
The documentation states:
Whether or not child properties should be implicitly validated if a matching validator can be found. By default this is false, and you should wire up child validators using SetValidator.
So setting this to true implies that child properties will be validated.
Solution 3:[3]
Pretty old question but for future generations - you can either use a child validator or define child rules inline as described in the official documentation: https://fluentvalidation.net/start#complex-properties
Solution 4:[4]
It depends on where you want to use your validators:
In the common scenario, where we have an application with N layers,
in the ASP.net layer, for the validation of View Models, DTOs or Commands (e.g. to achieve fail-fast validation), just enable ImplicitlyValidateChildProperties, as @StevenYates said:
services.AddMvc().AddFluentValidation(fv =>
{
fv.ImplicitlyValidateChildProperties = true;
});
When this is enabled, instead of having to specify child validators using SetValidator, MVC’s validation infrastructure will recursively attempt to automatically find validators for each property automatically.
IMHO, this is great, because besides being practical, it prevents us from forgetting some .SetValidator (...)!
Note that if you enable this behaviour you should not use SetValidator for child properties, or the validator will be executed twice.
But, in addition (or instead) of that, if you want to use FluentValidation in other layers (e.g. Domain), you need to use the SetValidator(...) method, as @t138 said, for example:
RuleFor(customer => customer.Address).SetValidator(new AddressValidator());
Doc: https://docs.fluentvalidation.net/en/latest/start.html#complex-properties
Solution 5:[5]
public class A
{
public B B { get; set; }
}
public class B
{
public int Id { get; set; }
}
public class AValidator : AbstractValidator<A>
{
public AValidator()
{
RuleFor(x => x.B).NotNull().SetValidator(new BValidator());
}
class BValidator : AbstractValidator<B>
{
public BValidator()
{
RuleFor(x => x.Id).NotEmpty().WithMessage("message ....");
}
}
}
----------------------------------------------------------------------
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddFluentValidation(fv =>
{
fv.RegisterValidatorsFromAssemblyContaining<Startup>();
fv.ImplicitlyValidateChildProperties = true;
});
}
Solution 6:[6]
You can use ChildRules method:
public class AValidator : AbstractValidator<A>
{
public AValidator()
{
RuleFor(x => x.Prop)
.ChildRules(x => x.RuleFor(b => b.Id))
.NotEmpty()
.WithMessage("Please ensure you have selected the A object");
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Aleksey L. |
| Solution 2 | Grigory Zhadko |
| Solution 3 | t138 |
| Solution 4 | Maicon Heck |
| Solution 5 | Zaid Qassim |
| Solution 6 | ????? ????? |
