17

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.

Crazylazy
  • 173
  • 1
  • 5

1 Answers1

23

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

Update 12/2020: The default value is now false for .NET 5.0.

~~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.

GoClimbColorado
  • 1,060
  • 3
  • 13
  • 28
Tseng
  • 61,549
  • 15
  • 193
  • 205
  • I'm having a little trouble with this. I have a similar issue. I am using Hangfire, and I need it to access my database to update it with some data from an API on a schedule. I tried setting `ValidatesScopes = true` in my service setup in Startup, but that didn't change anything in my Configure: I still get the error when setting up my service. I understand why MS did this, but it's annoying they are forcing me to do something I know worked fine in 1.1: as in, I don't have memory issues, etc. – Robert Burke May 15 '18 at 20:35
  • 1
    Furthermore, I change it from Singletion to Scoped, hoping since my DbContext is apparently Scoped, that Scoped inside Scoped would be fine and instead I get this error: 'Cannot resolve scoped service 'ArithmosDaily.IHangfireJobSchedulerService' from root provider.' – Robert Burke May 15 '18 at 21:14
  • @RobertBurke: `ValidatesScopes = true` is the default value... You probably want it `ValidateScopes = false` to **disable** this validation – Tseng May 15 '18 at 22:11
  • @Tseng Sorry, that was a copy/paste error. I *did* set it to false. – Robert Burke May 16 '18 at 01:06
  • 1
    Sorry, I've moved this to my own question. It's a little bit bigger and the above resolution has not helped me. Hopefully asking my own question will get me an answer. The above is more of an explanation, but not a practical implementation that helps me. Thanks, though! – Robert Burke May 16 '18 at 04:49
  • In what version was this `ValidateScopes` functionaity added, anyone knows? – Jim Aho Jul 03 '19 at 13:07
  • @JimAho: Iirc 2.0. .NET Core 1.x would just resolve from the application container w/o you noticing it (resulting in hard to track bugs and memory leaks) – Tseng Jul 03 '19 at 13:12
  • what about transient ? https://stackoverflow.com/questions/57620528/net-core-di-scope-validation-scoped-vs-transient – Royi Namir Aug 23 '19 at 06:17
  • Is this true for a .NET 6.0 console app using the generic host as well? It's not a asp.net app. I created a scope from the scopefactory and wrapped the services I want in scoped lifetime inside. Also my reading of the doc sounds like that this ValidateScopes flag only gets applied in hosted environments, not in Visual Studio. – Stack Undefined Jun 24 '22 at 02:03