Description
I came across this issue after a couple of hours of debugging an issue with the Blazor (.NET 6) service configuration. There seems to be an implicit assumption that is currently not covered by any of the existing specification / compliance tests in DependencyInjectionSpecificationTests
: When an instance of IServiceProvider
is requested from a scoped (non-root) service provider or a non-singleton instance that is created from such a service provider depends on an IServiceProvider
then that scoped service provider is resolved and not the root service provider.
There is already a test for singletons that is DependencyInjectionSpecificationTests.SingletonServiceCanBeResolvedFromScope
which works differently and always expects the "root service provider" to be injected.
As far as I can tell, the expected behavior is roughly this:
- If an
IServiceProvider
is requested, then that should normally resolve to the service provider instance on which that request is made, meaning that the scope of the injected service provider is preserved, unless... - If an
IServiceProvider
is injected into a singleton service, then the root service provider should be resolved because singletons are always "attached" to the root service provider to control their lifetime and injecting a scoped service provider instance would be pretty dangerous.
To check if I was the only person that was unaware of this implicit assumption, I added a new test to cover that and got the following results: Of the 8 currently included DI frameworks, 4 conform to this implicit assumptions and 4 fail the new tests.
Grace => FAIL
Autofac => FAIL
LightInject => FAIL
StashBox => FAIL
DryIoc => OK
StructureMap => OK
Lamar => OK
Unity => OK
At this point, I can almost guarantee that any DI container that doesn't satisfy this implicit assumption will run into problems when running even the basic Blazor project template. Particularly if that container does cover the singleton special case which seems to be true for all of the failing containers. Since that will end up in the same case I had issues with my Ninject integration where services are incorrectly resolved using the root service provider instead of the scoped service provider.
I can give more details on this exact Blazor scenario if needed - it mostly revolves around the Microsoft.AspNetCore.Components.NavigationManager
.
Of course, like all critical assumptions of Microsoft.Extensions.DependencyInjection, this one should also be covered by a compliance test and I will create a PR for that and update the tests for the currently failing external DI containers to exclude this test case using the SkippableDependencyInjectionSpecificationTests
mechanism.