Injecting a Scoped service into IHostedService

Cannot consume scoped service ‘IScoped’ from singleton ‘Microsoft.Extensions.Hosting.IHostedService’.

In our projects we are using IHostedService to run background processes. What I have seen is that when injecting a scoped service into the IHostedService you get a InvalidOperationException on startup. The first time you get this exception, it is takes some time to figure out what is going on. This blog post will help you to resolve the problem faster.

When injecting a scoped service into a IHostedService you get the following error:

System.InvalidOperationException: ‘Cannot consume scoped service ‘aspnetScopedInSingleton.BackgroundServices.IScoped’ from singleton ‘Microsoft.Extensions.Hosting.IHostedService’.’

The problem
You are implementing a IHostedService and inject a dependency that is scoped (for example a DbContext). Your program throws the InvalidOperationException when it is started. The exception is thrown because the IHostedService singleton itself is not created in a dependency injection scope. As result of this you cannot create dependencies declared as scoped.

Solution
To use a scoped object in a IHostedService you have to create dependency injection scope with the IServiceScopeFactory. Within this scope you can use the scoped services.

    public class BackgroundServiceConsumeScopedService : BackgroundService, IHostedService
    {
        public IServiceScopeFactory _serviceScopeFactory;
        public Class(IServiceScopeFactory serviceScopeFactory)
        {
            _serviceScopeFactory = serviceScopeFactory;
        }
        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            using (var scope = _serviceScopeFactory.CreateScope())
            {
                IScoped scoped = scope.ServiceProvider.GetRequiredService();

                //Do your stuff
            }
            return Task.CompletedTask;
        }

    }
    public interface IScoped { }

    public class Scoped : IScoped { }

Related posts
Background processing
Schedule services
Headless services
Using HttpClientFactory

When using a scoped service in a IHostedService it is important you think about why it is scoped. For example when you have a dbcontext, the objects life time will be the same as the scope where it is created. Keep the scope as small as possible to avoid errors that are caused by to much reuse, or long life time.

Advertisements

5 thoughts on “Injecting a Scoped service into IHostedService”

  1. Hi – I’m battling with IHostedService at this very moment!

    Would you use IHostedService to execute a long running task from an action method, or should IHostedService only be used for periodic tasks that run in the background? If you can execute from an action method, how would you pass additional parameters to ExecuteAsync?

    Liked by 1 person

    1. Hi Robin, basically would use the ExecuteAsync method to ‘administer’ your long running process. When using the BackgroundService class from the framework you are not able to change the parameters. In the blog post https://pgroene.wordpress.com/2018/05/31/run-scheduled-background-tasks-in-asp-net-core you can find some samples to implement the IHostedService interface yourself. If possible I would try to cut the ‘long’ running process into smaller parts to have more control over what is happening and for example handle when the application shuts down.

      Like

  2. Hi Peter, I’m facing with the same issue. Can you tell me is this independent class or this should be a part of startup class?
    For scheduled task, I re-used your solution that you provided on GitHub.
    Thanks in advance!

    Like

    1. When you start a new task from a scheduler, it does not have a scope. If you want to use classes that run in a scope like a dbconnection you should add the:
      using (var scope = _serviceScopeFactory.CreateScope())
      {
      IScoped scoped = scope.ServiceProvider.GetRequiredService();

      //Do your stuff
      }
      In the Do Your Stuff part you can use the scope.ServiceProvider.GetRequiredService to create the top level obect in you your scope that will do the processing.

      Like

      1. Hi, Peter.
        Thank you very much for your time and answer!
        Please take a look of this image: https://ibb.co/YjTLwPg
        I added this part of the code in ScheduleTask.cs but, I’m getting the error with a message: ‘The type arguments for method ‘ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider)’ cannot be inferred from the usage. Try specifying the type arguments explicitly. ‘.

        I tried to find solution, but with no succes.

        Thanks in advance!

        Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.