Assuming this registration, how should the dependency injection container possibly know which “singleton” (it’s not really a singleton when there are two of them) it should inject into the HomeController, or a different service, when they are all just depend on IUser
?
The type the dependency gets registered as, in your case IUser
, is the “key” which DI containers use to resolve the dependency. So two services that both depend on IUser
will get their dependency resolved in the same way. With a singleton lifetime, this means that both services get the same instance.
Service registrations are also usually replacing. So if you have one registration AddSingleton<X, Y>()
and then have another one AddSingleton<X, Z>()
, then the latter will replace the former. So all services dependending on X
will receive Z
.
DI containers, including the default container that ships with ASP.NET Core, do usually support resolving all registrations by depending on IEnumerable<X>
instead. But for this example this just means that a services would get both Y
and Z
.
The closest thing you are looking for are keyed or named dependencies. While these are supported in some DI containers, they are technically not part of dependency injection and as such often deliberately absent from many containers, including the ASP.NET Core one. See this answer for more details on that and for some idea to get around that.
To get back to your use case, you should really think about what you are actually doing there. If you have two “singleton” instances of UserService
, you should really think about why that is the case: Why isn’t there just one? And if there is support for multiple, why not register it as transient?
More importantly, what would possibly differ between those two instances? After all, they are both instances of the same implementation, so there isn’t much that they can do differently.
If you can identify that, and also confirm that this is something that actually makes the instances different, then consider splitting this up in the type hierarchy as well. It’s difficult to explain this without having a use case here, but what you should try is to end up with two different interfaces that each do exactly what each dependent service type needs. So HomeController
can depend on IUserA
, and others can depend on IUserB
(please choose better names than this).