Reputation: 1443
I am having trouble getting FluentValidation to work with a collection of objects. My controller POST action takes in an IEnumerable of objects like below. When I post to an action that takes a single EventInputDto
, with an incorrectly formatted Url
property, my validation occurs successfully. When I post to a collection of EventInputDto
, it does not work and does no validation.
If I use regular MVC Attributes (i.e. required / email), they work with collections as well as single objects. How do I get this to work with FluentValidation? I am not working with inner collections so I'm not sure why it does not work as intended.
public async Task<IActionResult> CreateEventCollection([FromBody] IEnumerable<EventInputDto> events)
{
if (!ModelState.IsValid)
{
return UnprocessableEntity(ModelState); //does not work
}
}
My validators are setup using generics because I am using separate models for inputs and updates.
public class EventManipulationValidator<T> : AbstractValidator<T> where T : EventManipulationDto
{
public EventManipulationValidator()
{
RuleFor(manipulationDto => manipulationDto.Title).NotNull().WithMessage("Title cannot be blank")
.Length(1, 50);
RuleFor(manipulationDto => manipulationDto.Message).NotNull().WithMessage("Message cannot be blank")
.Length(1, 1000);
RuleFor(manipulationDto => manipulationDto.ScheduledTime).NotNull().WithMessage("Scheduled Time cannot be blank");
RuleFor(inputDto => inputDto.Url).Matches(@"https://.*windows\.net.*").WithMessage("The url must be valid and stored on Azure");
}
}
As my CreateEventCollection action takes in an IEnumerable of EventInputDto, my validator for EventInputDto is setup as below:
public class EventInputValidator : EventManipulationValidator<EventInputDto>
{
public EventInputValidator()
{
//all property validators are inherited from EventManipulationValidator
}
}
public class EventInputCollectionValidator : AbstractValidator<IEnumerable<EventInputDto>>
{
public EventInputCollectionValidator()
{
RuleForEach(p => p).SetValidator(new EventManipulationValidator<EventInputDto>());
}
}
Below are my models for reference:
EventManipulationDto
public abstract class EventManipulationDto
{
public string Title { get; set; }
public string Message { get; set; }
public string Url { get; set; }
public DateTime? ScheduledTime { get; set; }
}
EventInputDto
public class EventInputDto : EventManipulationDto
{
//all properties inherited from base class
}
Upvotes: 5
Views: 3358
Reputation: 1443
After going through the list of open/closed issues on the project GitHub, it seems that not all of my approach is required. There is no need for my `EventInputCollectionValidator. FluentValidation no longer requires explicitly defining an IEnumerable validator like I defined above.
It's enough to define a base AbstractValidator or as in my case an inherited validator from a parent class.
The only change needed to get it to work was in my startup.cs when registering fluentvalidation. I needed to explicitly add ImplicitlyValidateChildProperties = true
. Didn't realize this was required as I thought this was for validating child property collections and not the parent collection objects. Works perfectly now.
.AddFluentValidation(fv => {
fv.RunDefaultMvcValidationAfterFluentValidationExecutes = true;
fv.RegisterValidatorsFromAssemblyContaining<Startup>();
fv.ImplicitlyValidateChildProperties = true;
});
Upvotes: 5