What is ServiceProviderOptions.ValidateScopes exactly? I feel I couldn't understand completely what it does under the hood. I've come across this with a tutorial, but no explanation.
问题:
回答1:
I assume you are speaking about this piece of code:
services.BuildServiceProvider(new ServiceProviderOptions
{
ValidateScopes = true
});
// or
services.BuildServiceProvider(true); // or false
?
The ASP.NET Core Provider has a mechanic which validates if a scoped service is resolved by a singleton container. ASP.NET Core has two kinds of containers. The main, singleton container which is valid for the life-time of the application and scoped containers for every request.
This option will prevent resolving of scoped services from the singleton container, that is if you accidentally try to resolve a scoped service within Configure
method, you will get an exception. Whereas if you disable it you shouldn't.
public void Configure(IApplicationBuilder app)
{
// will throw exception, since by default DbContext is registered as scope
app.ApplicationServices.GetRequiredService<MyDbContext>();
}
The exception is something similar to
InvalidOperationException: Cannot resolve 'IExampleService' from root provider because it requires scoped service 'MyDbContext'.
This behavior is there to prevent memory leaks and resolving scoped services (which are supposed to be short-lived) from singleton container, essentially making this services quasi-singletons too (because they won't get disposed until the container gets disposed and the singleton container only gets disposed when the application is shut down).
The correct way to resolve scoped services within i.e. Configure
method is this
// get scoped factory
var scopedFactory = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>();
// create a scope
using (var scope = scopedFactory.CreateScope())
{
// then resolve the services and execute it
var context = scope.ServiceProvider.GetRequiredService<MyDbContext>();
}
// here, the child (scoped) container will be disposed and all scoped and transient services from it
The default value is true
and you should leave it like that unless you know exactly what you are doing otherwise you risk nasty memory leaks (or object already disposed exceptions) by unreleased services.