Scrutor icon indicating copy to clipboard operation
Scrutor copied to clipboard

AsImplementedInterfaces() registering too much

Open danspam opened this issue 7 years ago • 9 comments

I understand that AsImplementedInterfaces() registers all implemented interfaces, however this is sometimes too much. Take for instance, the FluentValidation library, you may scan with the following:

.AddClasses(c => c.AssignableTo(typeof(IValidator<>))).AsImplementedInterfaces()

This will pickup all the AbstractValidator<T> implementations you have, but this class implements the following interfaces:

IValidator<T>
IEnumerable
IEnumerable<IValidationRule>
IValidator

Which means you get entries for all of these, not just the desired IValidator<T> and I need to do the following to get rid of the superfluous entries:

services.RemoveAll<IValidator>();
services.RemoveAll<IEnumerable>();
services.RemoveAll<IEnumerable<IValidationRule>>();

Is there any way to do this without having to remove the extra entries afterwards?

danspam avatar Oct 31 '18 02:10 danspam

Is there any way to do this without having to remove the extra entries afterwards?

Not really. You either have to filter them out using a custom implementation of AsImplementedInterfaces (it's pretty straight forward):

https://github.com/khellang/Scrutor/blob/4bb8ff4d3f936e02f11d9ebcabc68bd424728411/src/Scrutor/ServiceTypeSelector.cs#L50-L55

Or remove the extra entries like you're already doing.

I guess we could look at automatically filtering out IEnumerable interfaces as those doesn't make much sense to register (to me). The problem is that it would be a breaking change.

khellang avatar Oct 31 '18 08:10 khellang

Can I ask why you care about the extra entries? Just for debugging purposes, or?

khellang avatar Oct 31 '18 08:10 khellang

I'm experimenting with shifting DI containers and the background noise makes it impossible to know what is going on

danspam avatar Nov 01 '18 05:11 danspam

I've noticed the same behavior with FluentValidation library, Scrutor adds a lot of unnecessary stuff to the container.

It would be great to have some way of fine-tunning AsImplementedInterfaces setup or even make it more extensible.

Another point is that there are good reflection extensions that could be exposed to be used inside AddClasses, like IsAssignableTo, for instance.

natenho avatar Mar 08 '19 20:03 natenho

I think it makes sense to exclude IEnumerable (as that has built-in semantics in the container), but other than that, I think you'll have to pass your own "rules" in the form of a delegate passed to As(Func<Type, IEnumerable<Type>> selector). That should let you customize the types however you want.

khellang avatar Jun 06 '19 08:06 khellang

Just checking in with this, is there a modern way to do this or is this thread still correct?

trullock avatar May 28 '20 18:05 trullock

I came across this issue for a different reason: I am refactoring our code and moving some services to dotnet from Framework but I just get an exception: System.TypeLoadException HResult=0x80131522 Message=Could not load type 'System.Web.Hosting.IRegisteredObject' from assembly 'System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.

I do not actually need to register IRegisteredObject but it also seems like there is no way to tell Scrutor to ignore this interface. I can do it for classes but it does not seem as though I can do it for interfaces.

THammond9 avatar Feb 28 '22 20:02 THammond9

I do not actually need to register IRegisteredObject but it also seems like there is no way to tell Scrutor to ignore this interface.

@THammond9 There is. It's mentioned as a workaround in this issue.

I think a short-term non-breaking fix for this issue would be to introduce an overload of AsImplementedInterfaces that takes a filter predicate so people could filter out what they don't want.

If anyone wants to send a PR before I get to it, that would be cool 😎

khellang avatar Mar 01 '22 06:03 khellang

I've added an overload to AsImplementedInterfaces that lets you filter the interfaces you'd like to register using a predicate and pushed it to NuGet as part of v4.1.0 😄 I'll leave the issue open to track the breaking change of filtering out some common types by default,

khellang avatar Mar 02 '22 13:03 khellang

Is there a final example of how to register all of the validators for the FluentValidation library with Scrutor? Which interfaces need to be filtered and how to specify the filter?

mmajcica avatar Sep 29 '22 07:09 mmajcica

For others looking at this, the following is not the most elegant solution but it works:

.AddClasses(classes => classes.AssignableTo(typeof(IValidator<>)))
                    .AsImplementedInterfaces(x => x != typeof(IEnumerable<IValidationRule>) && x != typeof(IValidator) && x != typeof(IEnumerable))
                    .WithScopedLifetime());

mmajcica avatar Sep 29 '22 08:09 mmajcica

I've added a filter for IEnumerable and IEnumerable<T> for upcoming major version, as I can't imagine why people would want to register those service types (I'm not even sure if/how it would work).

I really don't want to get into the business of maintaining a list of types that should or shouldn't be registered in the container. The overload taking Func<Type, bool> lets people make these decisions themselves 😄

khellang avatar Sep 05 '23 08:09 khellang