-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AddValidatorsFromAssemblyContaining would register Validators twice #2182
Comments
@peterwurzinger But I also like the idea of not creating duplicates in the DI container and suggest to consider throwing the You can check for it in AddScanResult method: private static IServiceCollection AddScanResult(this IServiceCollection services, AssemblyScanner.AssemblyScanResult scanResult, ServiceLifetime lifetime, Func<AssemblyScanner.AssemblyScanResult, bool> filter) {
bool shouldRegister = filter?.Invoke(scanResult) ?? true;
if (shouldRegister) {
//Check if ValidatorType is already in DI container
if(services.Any(s => s.ServiceType == scanResult.InterfaceType || s.ServiceType == scanResult.ValidatorType)
throw new InvalidOperationException($"An attempt was made to add a duplicate validator to the container. InterfaceType: {typeof(scanResult.InterfaceType)}. ValidatorType: {typeof(scanResult.ValidatorType)}")
....
}
return services;
}
|
I'm not sure if I understand what you mean. The problem basically boils down to hosting environments, where multiple identical calls to
Honestly I would disagree with that. There certainly are situations, where multiple calls to services
.AddPricingFeatures() //registers pricing validators by AddValidatorsFromAssembly() <-- This would not throw
.AddSalesFeatures() //registers sales validators by AddValidatorsFromAssembly() <-- This would throw
.AddInventoryFeatures() //registers inventory validators by AddValidatorsFromAssembly() <-- This would also throw Imho those subsequent call to services.AddAuthentication().AddAuthentication().AddAuthentication() and neither would it throw, nor register the authentication services thrice. |
I've just checked which methods are used in Microsoft IServiceCollection extension methods and came to the conclusion that I was wrong about throwing exceptions I think it's worth removing the possibility of double registration of services in DI and agree with your idea of adding TryAdd to AddValidatorsFrom....() But what approach will be better?
@peterwurzinger What do you think about those second and third ideas? |
In my personal opinion But that all being said, that's something for @JeremySkinner to decide, I'm only the messenger. |
I'm very open to switching to using TryAdd internally, I don't see any problems with that. If you want to submit a PR for this I'll happily review it. |
@JeremySkinner Alright, I opened a fix via #2184 , feel free to review at your convenience |
I've pushed out the 11.9 release with this change |
FluentValidation version
11.8.1
ASP.NET version
(ASP).NET Core 8
Summary
I honestly don't know if it is an issue, but it manifested as one to me when it occured.
2 (but actually any amount of) calls to
AddValidatorsFromAssemblyContaining(<assembly>)
would register every validator in the matching assembly 2 times. Clients, that retrieve something likeIEnumerable<IValidator<TTarget>>
via DI would get 2 instances of the same validator, potentially leading to executing it twice. Or thrice, or ... you get the point.What sounds as an exotic use case in the first place, isn't too exotic for applications that make use of Vertical Slice Architecture. There the following structures are quite common:
-- Validators of Feature A (registered via FeatureA.ServiceCollectionExtensions.AddFeatureAServices)
-- Validators of Feature B (registered via FeatureA.ServiceCollectionExtensions.AddFeatureBServices)
-- ...
It basically boils down to the registrations in
FluentValidation/src/FluentValidation.DependencyInjectionExtensions/ServiceCollectionExtensions.cs
Lines 95 to 106 in 51e365b
Here the descriptors are added via the
Add
method.Changing those to
TryAdd
, that verifies if a corresponding service descriptor is already contained in the service collection, would resolve this issue.But as said, I can't tell if this is an inteded behavior for a use case that I currently cannot see. In that case a parameter for example could provice both options:
Steps to Reproduce
The text was updated successfully, but these errors were encountered: