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.

2 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?

    Like

    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

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.