When calling services.AddSimpleInjector(), Simple Injector allows pulling dependencies from the built-in .NET Core configuration system (through a mechanism called "cross wiring"). When a Simple Injector-composed component depends on a service that is registered in the built-in configuration system, it will request that service from there.
In case such dependency is scoped, however, the .AddSimpleInjector() integration ensures that such service is resolved from .NET Core's IServiceScope. It does so by resolving the IServiceScope from a Simple Injector Scope. In other words, IServiceScope itself becomes a Scoped dependency in Simple Injector.
Within the context of ASP.NET Core, however, this behavior of having one IServiceScope per Simple Injector Scope, has some downsides. ASP.NET Core allows request-specific data to be retrieved using services that are stored in a IServiceScope. This would mean that, in case you start a new Simple Injector Scope, you lose the ability to get this information from core services.
This is why the ASP.NET Core integration for Simple Injector changes this scoping behavior and ensures that within a single web request, Simple Injector always uses the same (by ASP.NET Core created) IServiceScope instance, independently of how many (nested) Scope instances are created.
An unfortunate consequence of this, however, is that a cross-wired DbContext will be reused for the duration of a web request, even if nested scopes are created. This is -especially- problematic when using Blazor Service, because Blazor will let a IServiceScope live "for as long as the user is on the page with the Blazor Component (i.e., as long as the SignalR connection is open)." (as described here) This, again, is problematic, because this could lead to concurrency issues, because the user is able to run requests in parallel.
To accommodate this, the Simple Injector user should be able to change how IServiceScope instances are reused. I see three options:
The (default) ASP.NET Core integration option, where an IServiceScope is reused for the duration of the request/SignalR connection/Blazor page.
The (default) ServiceCollection integration, where each Simple Injector Scope gets its own newly created IServiceScope. This will cause loss of request-specific data, because the Scope that Simple Injector wraps around a request, will cause the creation of a new IServiceScope, rather than using the request's IServiceScope.
A new hybrid option, where Simple Injector will reuse the request's IServiceScope for the request's root Scope, but where all nested scopes get their own (new) IServiceScope.
When calling
services.AddSimpleInjector()
, Simple Injector allows pulling dependencies from the built-in .NET Core configuration system (through a mechanism called "cross wiring"). When a Simple Injector-composed component depends on a service that is registered in the built-in configuration system, it will request that service from there.In case such dependency is scoped, however, the
.AddSimpleInjector()
integration ensures that such service is resolved from .NET Core'sIServiceScope
. It does so by resolving theIServiceScope
from a Simple InjectorScope
. In other words,IServiceScope
itself becomes aScoped
dependency in Simple Injector.Within the context of ASP.NET Core, however, this behavior of having one
IServiceScope
per Simple InjectorScope
, has some downsides. ASP.NET Core allows request-specific data to be retrieved using services that are stored in aIServiceScope
. This would mean that, in case you start a new Simple InjectorScope
, you lose the ability to get this information from core services.This is why the ASP.NET Core integration for Simple Injector changes this scoping behavior and ensures that within a single web request, Simple Injector always uses the same (by ASP.NET Core created)
IServiceScope
instance, independently of how many (nested)Scope
instances are created.An unfortunate consequence of this, however, is that a cross-wired
DbContext
will be reused for the duration of a web request, even if nested scopes are created. This is -especially- problematic when using Blazor Service, because Blazor will let aIServiceScope
live "for as long as the user is on the page with the Blazor Component (i.e., as long as the SignalR connection is open)." (as described here) This, again, is problematic, because this could lead to concurrency issues, because the user is able to run requests in parallel.To accommodate this, the Simple Injector user should be able to change how
IServiceScope
instances are reused. I see three options:IServiceScope
is reused for the duration of the request/SignalR connection/Blazor page.Scope
gets its own newly createdIServiceScope
. This will cause loss of request-specific data, because theScope
that Simple Injector wraps around a request, will cause the creation of a newIServiceScope
, rather than using the request'sIServiceScope
.IServiceScope
for the request's rootScope
, but where all nested scopes get their own (new)IServiceScope
.Related to: