Skip to content
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

Calling .AsImplementedInterfaces() can result is duplicate service descriptors getting registered #20

Closed
eric-davis opened this issue Feb 2, 2017 · 6 comments
Milestone

Comments

@eric-davis
Copy link

If a class implements multiple interfaces and the following pseudo-code is executed multiple times for each of the different interface types that class implements, the same service descriptor will be registered multiple times.

services.Scan( x => { x.FromAssemblies([ASSEMBLY_COLLECTION]) .AddClasses(classes => classes.AssignableTo([INTERFACE_TYPE])) .AsImplementedInterfaces() .WithTransientLifetime(); });

@adamhathcock
Copy link
Contributor

If you have a class Class1 with interfaces I1 and I2 then you should get two registrations with both interfaces against Class1 when using AsImplementedInterfaces()

I read your pseudocode as saying it's finding Class1 because it matches INTERFACE_TYPE and then you're calling AsImplementedInterfaces() to get two registrations.

Isn't that is what is happening? What do you expect to happen?

@eric-davis
Copy link
Author

eric-davis commented Feb 2, 2017

Not quite. Let me see if I can better explain what I am running into.

If I have a class (MyClass) that implements both Interface1 and Interface2 and I perform a .Scan() using the .AddClasses(classes => classes.AssignableTo(typeof(Interface1)).AsImplementedInterfaces() selectors. Then 2 ServiceDescriptors are added to the services collection: 1 for MyClass + Interface1 and 1 for MyClass + Interface2. No issues at this point.

But if I then execute another .Scan() using the .AddClasses(classes => classes.AssignableTo(typeof(Interface2)).AsImplementedInterfaces() selectors, 2 more ServiceDescriptors are added to the services collection: 1 for MyClass + Interface1 and 1 for MyClass + Interface2. Now I have 4 total services entries: 2 for MyClass + Interface1 and 2 for MyClass + Interface2.

I see that this is the result of using the ICollection<ServiceDescriptor>.Add() method in the ISelector.Populate() method in the LifetimeSelector class. Using the TryAdd() extension method available in the Microsoft.Extensions.DependencyInjection.Extensions library instead would avoid the duplicates. Or maybe a new selector type could be defined to allow the consumer to choose whether or not duplicate ServiceDescriptors should be allowed? This could effectively add a logic condition that would determine if Add() or TryAdd() should be used.

@adamhathcock
Copy link
Contributor

Ahh, I see.

It's not a problem with AsImplementedInterfaces() or any feature specifically. It's the fact if you run Scan twice then multiple ServiceDescriptor equivalent objects are added because it uses Add and not TryAdd

Question for @khellang but maybe the solution is making a TryScan that uses TryAdd ?

@eric-davis
Copy link
Author

Yeah. Something like that would be helpful. The issue arises for me because I am trying to support the ability to scan for a variable number of interfaces and am trying to abstract the Scrutor code away via a custom extension method. I guess I could try to build up the entire list of interfaces and attempt to do just one Scan operation. I haven't tested that yet, but maybe that wouldn't result in the duplicates. I may see if I can put a PR together that meets my needs.

@eric-davis
Copy link
Author

Nevermind... I found a way to make this work as I intended without calling Scan more than once.

@khellang
Copy link
Owner

khellang commented Apr 7, 2017

@eric-davis Thanks to @adamhathcock (#22), there's now support for calling UsingRegistrationStrategy(RegistrationStrategy.Skip) (as seen here). That should prevent Scrutor from adding duplicate entries for the same service.

@khellang khellang modified the milestone: v1.11.0 Apr 10, 2017
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

No branches or pull requests

3 participants