Cannot Consume Scoped Service From Singleton – A Lesson In Core DI Scopes

While helping a new developer get started with Core, they ran into an interesting exception :

InvalidOperationException: Cannot consume scoped service from singleton.

I found it interesting because it’s actually the Service DI of Core trying to make sure you don’t trip yourself up. Although it’s not foolproof (They still give you enough rope to hang yourself), it’s actually trying to stop you making a classic DI scope mistake. I thought I would try and build up an example with code to first show them, then show you here! Of course, if you don’t care about any of that, there is a nice TL;DR right at the end of this post!

The Setup

So there is a little bit of code setup before we start explaining everything. The first thing we need is a “Child” service :

The reason we have a property here called “CreationCount” is because later on we are going to test if a service is being created on a page refresh, or it’s re-using existing instances (Don’t worry, it’ll make sense!)

Next we are going to create *two* parent classes. I went with a Mother and Father class, for no other reason that the names seemed to fit (They are both parent classes). They also will have a creation count, and reference the child service.

Finally, we should create a controller that simply outputs how many times the services have been created. This will help us later in understanding how our service collection is created and, in some circumstances, shared.

The Scoped Service Problem

The first thing we want to do, is add a few lines to the ConfigureServices method of our startup.cs. This first time around, all services will be singletons.

Now, let’s load our page and refresh if a few times and see what the output is. The results of 3 page refreshes look like so :

So this makes sense. A singleton is one instance per application, so no matter how many times we fresh the page, it’s never going to create a new instance.

Let’s change things up, let’s make everything transient.

And then we load it up 3 times.

It’s what we would expect. The “parent” classes go up by 1 each time. The child actually goes up by 2 because it’s being “requested” twice per page load. One for the “mother” and one for the “father”.

Let’s instead make everything scoped. Scoped means that a new instance will be created essentially per page load (Atleast that’s the “scope” within Core).

And now let’s refresh out page 3 times.

OK this makes sense. Each page load, it creates a new instance for each. But unlike the transient example, our child creation only gets created once per page load even though two different services require it as a dependency.

Right, so we have everything as scoped. Let’s try something. Let’s say that we decide that our parents layer should be singleton. There could be a few reasons we decide to do this. There could be some sort of “cache” that we want to use. It might have to hold state etc. The one reason we don’t want to make it singleton is for performance. Very very rarely do I actually see any benefit from changing services to singletons. And the eventual screw ups because you are making things un-intuitively singletons is probably worse in the long run.

We change our ConfigureServices method to :

We hit run and….

So because our ChildService is scoped, but the FatherService is singleton, it’s not going to allow us to run. So why?

If we think back to how our creation counts worked. When we have a scoped instance, each time we load the page, a new instance of our ChildService is created and inserted in the parent service. Whereas when we do a singleton, it keeps the exact same instance (Including the same child services). When we make the parent service a singleton, that means that the child service is unable to be created per page load. Core is essentially stopping us from falling in this trap of thinking that a child service would be created per page request, when in reality if the parent is a singleton it’s unable to be done. This is why the exception is thrown.

What’s the fix? Well either the parent needs to be scoped or transient scope. Or the child needs to be a singleton itself. The other option is to use a service locator pattern but this is not really recommended. Typically when you make a class/interface singleton, it’s done for a very good reason. If you don’t have a reason, make it transient.

The Singleton Transient Trap

The interesting thing about Core catching you from making a mistake when a scoped instance is within a singleton, is that the same “problem” will arise from a transient within a singleton too.

So to refresh your memory. When we have all our services as transient :

We load the page 3 times, and we see that we create a new instance every single time the class is requested.

So let’s try something else. Let’s make the parent classes singleton, but leave the child as a transient.

So we load the page 3 times. And no exception but…

This is pretty close as having the child as scoped with the parents singletons. It’s still going to give us some unintended behaviour because the transient child is not going to be created “everytime” as we might first think. Sure, it will be created everytime it’s “requested”, but that will only be twice (Once for each of the parents).

I think the logic behind this not throwing an exception, but scoped will, is that transient is “everytime this service is requested, create a new instance”, so technically this is correct behaviour (Even though it’s likely to cause issues). Whereas a “scoped” instance in Core is “a new instance per page request” which cannot be fulfilled when the parent is singleton.

Still, you should avoid this situation as much as possible. It’s highly unlikely that having a parent as a singleton and the child as transient is the behaviour you are looking for.


A Singleton cannot reference a Scoped instance.


Join over 3.000 subscribers who are receiving our weekly post digest, a roundup of this weeks blog posts.
We hate spam. Your email address will not be sold or shared with anyone else.


    1. I ran into this because Assembly Microsoft.EntityFrameworkCore, Version= AddDbContext registers the application’s context as a scoped service.

  1. One scenario where a singleton may need a transient is when the child is a database repository. The singleton may need this to initialize a collection, but after that, the transient repository will never be used…so things work out. Just be sure to init your parent singleton in ConfigureServices by calling serviceProvider.GetService.

    1. @paultechguy can you perhaps elaborate on this? I need a singleton service that will keep all my configuration settings from the database but I get the same issue since my Context is DI into the Service I want make singleton.

      1. You would need to inject them both independently. Which would make sense as a Context is a living object, it’s not a setting.

      2. One way to accomplish this is to make your Configuration a singleton, but make your data a transient or scoped, depending on how may times it can be called, while introducing a transient or scoped configuration loader. This configuration loader should ask the configuration singleton if the singleton is loaded. If the singleton says that it is loaded, the loader should not invoke the data, it can actually dispose it and move on.

  2. I had created a customeLogger inherited from ILogger which is registerd by core as Singlton internally.
    I want to use a scoped variable inside my CustomLogger code to log some transactionid for each request.So that developers just log their message and custom logger take care of all other associated data to be logged. I used IHttpContextAccesser to resolve scoped object inside CustomLogger. How ever in high load it is not giving correct scoped object. Any body can help…

  3. services.AddSingleton();

    Seems to me the above is allowed because you can then have some sort of stateless service class handling parts of your logic. Same stateless service can then be used for the above singleton but also for other transient parts of your code base.

    Just my two cents.

  4. Very good explanation!
    For your information, I met this exception when I wanted to work with IHostedService.
    IHostedService allows creating a background process in your ASP.Net core service. My first reflex in the background service was to access to my database by using repository classes and I had the error “InvalidOperationException: Cannot consume scoped service from singleton.” because my repository classes were scoped.
    What is weird is when I decompiled the class containing extension method AddHostedService, I got this

    The only solution nowadays is to use IServiceScopeFactory to create its own dependencies in the hosted service.

    1. So for background processes in .NET Core, you actually need to manually create scopes because the hosted service itself is not run inside a “scope”. Buried in the Microsoft Docs they have a good example of what you need to do :

      Is there a reason why your repository itself is scoped and not the DBContext only? I guess I can’t think of anything bad off the top of my head, but you’ve also made the decision to make the repository itself scoped so I’m just interested 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *