question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Question]How to write validator for collection model binding in ASP.NET Core?

See original GitHub issue

System Details

  • FluentValidation version: FluentValidation.AspNetCore 8.6.2
  • Web Framework version: ASP.NET Core 2.2

Issue Description

Asp.Net Core support collection binding like this

[ApiController]
public class ClassroomController : ControllerBase {
	
	[HttpPost]
	public IActionResult CreateFromStudent([FromBody]IEnumerable<Student> students) {
                  // Code for create Classroom
	}
}

Let say my Student will look like this

public class Student 
{
    public Teacher Teacher{get;set;}
    //Some additional properties
}

Now want to validate that all students in IEnumerable<Student> students has the same teacher. The documentation for Collection validator https://docs.fluentvalidation.net/en/latest/collections.html seems not cover this scenario. How do I write a validator to accomplish this without creating a wrapper complex type with the collection as a property?

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
JeremySkinnercommented, Mar 6, 2020

Hi, this isn’t something that should be done in the ServiceProviderValidatorFactory, but rather is something you should set up explicitly with your container registrations.

You’re correct that if your action parameter is an IEnumerable<T>, then MVC will instantiate a List<T> - this is because MVC’s model binding process doesn’t actually know your intent when you specify an interface as an action method parameter, so it guesses and creates a List, which is the type that’s then passed into the validation infrastructure.

Personally I’d always recommend using explicit concrete types as action method parameters because of this (ie explicitly specify either List<T> or T[]). If your validator type directly matches the type of the action parameter (ie both are using List), then this will all just work without any issues.

However if you want to continue to use IEnumerable in your validator then you’ll need to be explicit about this in your container registration. The T in AbstractValidator<T> is contravariant, so you should be able to register a mapping with the container for IValidator<List<Student>> to StudentValidator (where StudentValidator inherits AbstractValidator<IEnumerable<T>>). If you set this up with an explicit call to services.AddTransient in your application startup routine then I believe this should work fine.

1reaction
lamLeXcommented, Mar 6, 2020

Hi @JeremySkinner , Although the code is compiled for the Validator and registered in the DI, the validation is not triggered upon model binding validation stage. I observed this behavior by setting the breakpoint in the delegate passed to Must() image

The code passed the validation and reached the code thats run after validation middleware although the input is invalid image

After some debugging and troubleshooting, I found out that my model is actually type of List<T> instead of IEnumerable<T>. Due to the nature of Microsoft DI, it only matches the exact type. The FluentValidationClientModelValidatorProvider only have IValidator<IEnumerable<T>> instead of IValidator<List<T>>; hence, it couldn’t find my validator for List<T>

I wonder if we could do anything in ServiceProviderValidatorFactory.CreateInstance() to accommodate this scenario?

Read more comments on GitHub >

github_iconTop Results From Across the Web

NET Core, binding string to collection with validation
validate value of property before converting (applying regular expression). Here's model: class FooParams { [Required] [RegularExpression("^\\d ...
Read more >
Model validation in ASP.NET Core MVC and Razor Pages
Model validation occurs after model binding and reports errors where data doesn't conform to business rules. For example, a 0 is entered in...
Read more >
Chapter 6. The binding model: retrieving and validating user ...
Model binding extracts values from a request and uses them to create .NET objects that are passed as method parameters to the action...
Read more >
Model Binding in ASP.NET Core
The record of what data is bound to the model, and any binding or validation errors, is stored in ControllerBase.ModelState or PageModel.
Read more >
Validation Attributes | ASP.NET Core Controls
Validation Attributes ; Compare, Validates that two properties in a model match. Built-in ; Range, Validates that a property value falls within a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found