Skip to content

Conversation

@peterwurzinger
Copy link

Fixes #2182

A few thoughts on that:

  • I wrote unit tests, but had to reference FluentValidation.DependencyInjectionExtensions.csproj from the test project to not create a whole new project for one test class. But feel free to move it around as you like.
  • Creating ServiceCollections to test the behavior required a new package reference on Microsoft.Extensions.DependencyInjection. I referenced the newest version of that package (8.0.0), as it is compatible with netstandard2.0. This does not reflect the runtime environments of projects targeting .NET 6 or .NET 7, as corresponding versions of that package would be used by an enclosing framework version. But since it likely doesn't make a difference and to maintain readability, I didn't include the conditional TFM-madness in the project file. If that is desired, just ping me and I will submit it later.
  • I tried to adhere to the coding style, naming and formatting that I saw. But also feel free to reformat as you like.

…ly once for each validator type and as IValidator<Target>
if (shouldRegister) {
//Register as interface
services.Add(
services.TryAddEnumerable(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you use TryAddEnumerable and not TryAdd here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The desired behavior is to register every validator both

  • as itself (serviceType == implementationType) to be able to resolve as itself
  • as IValidator<Target> (serviceType = IValidator<Target>, implementationType = itself) to be able to inject IEnumerable<IValidator<Target>>

The first use case is covered via TryAdd, since it ensures that only one instance per serviceType is being registered. Multiple calls to AddValidatorsFromAssembly will therefore not lead to registering validators twice.
The second use case needs TryAddEnumerable, since that method matches the combination of serviceType and implementationType. As the name suggests, you can register multiple implementation types (e.g. SomePartialModelValidator, SomeOtherPartialModelValidator) as the same serviceType (e.g. IValidator<Model>).
TryAdd(interfaceType, validatorType) would lead to only the first validator for a validation target being registered and every other being ignored.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to be careful about using TryAddEnumerable here, typically you only want 1 validator to be registered for a specific type, so the behaviour of only having the first validator being registered and ignoring the rest might be preferable. What happens if you register multiple validators for the same type and then try and resolve just 1, does it return the first or throw an exception? If the former, then this is fine but if it throws then we'll need to use TryAdd instead

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if you register multiple validators for the same type and then try and resolve just 1, does it return the first or throw an exception?

Well, it would not throw, but inject the last serviceType that was registered - been there, done that, spent hours debugging that case...
But as far as I can tell that behavior is very similar if not identical to using services.Add() or services.Add{Lifetime}() instead (see https://dotnetfiddle.net/FIKgHi and https://dotnetfiddle.net/ZDchVy). So since this actually was the core of the problem, i thought it was intentional to have multiple IValidator<SameModel> right away.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok perfect, that should be fine then

@JeremySkinner JeremySkinner merged commit 9125e11 into FluentValidation:main Dec 21, 2023
@JeremySkinner
Copy link
Member

Merged, thanks

@FluentValidation FluentValidation deleted a comment from lokrain Dec 21, 2023
@LeftTwixWand
Copy link

Spend 3 hours to understand, that IList is not supported... #2182

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AddValidatorsFromAssemblyContaining would register Validators twice

4 participants