Search code examples
c#asp.net-coredependency-injectionservice

How can you dependency inject an service into an IHostedService (scheduled job)?


The intend: I want to build a cronjob, that overrides incache memory with the current data. It should be a separate service.

I have an IHostedService called TimedHostedService and a custom service called ExampleService. Example should be injected into TimedHostedService, so it can call a method from ExampleService. ExampleService should be the only service to override the memory

The Problem: Program crashes when it tries to inject ExampleService into TimedHostedService. The following error message comes.

AggregateException: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: Microsoft.Extensions.Hosting.IHostedService Lifetime: Singleton ImplementationType: Example_Project.Backend.Job.TimedHostedService': Cannot consume scoped service 'Example_Project.Services.IExampleService' from singleton 'Microsoft.Extensions.Hosting.IHostedService'.) Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(IEnumerable serviceDescriptors, ServiceProviderOptions options)

InvalidOperationException: Error while validating the service descriptor 'ServiceType: Microsoft.Extensions.Hosting.IHostedService Lifetime: Singleton ImplementationType: Example_Project.Backend.Job.TimedHostedService': Cannot consume scoped service 'Example_Project.Services.IExampleService' from singleton 'Microsoft.Extensions.Hosting.IHostedService'.

The code

StartUp.cs

public void ConfigureServices(IServiceCollection services)
    {
        /* Add MemoryCache */
        services.AddMemoryCache();

        /* Add CronJob / Scheduled Job */
        services.AddHostedService<TimedHostedService>();

        /* Add Dependency Injection of ExampleService */
        services.AddScoped<IExampleService, ExampleService>();
}

ExampleService.cs

public interface IExampleService
{
    void SetExample();
    IInventoryArticle[] GetExamples();
}

public class ExampleService : IExampleService
{
    public Examples[] GetExamples()
    { return null; }

    public void SetExample()
    { }

}

TimedHostedService.cs

public class TimedHostedService : IHostedService, IDisposable
    {
        private readonly ILogger<TimedHostedService> _logger;
        private Timer _timer;
        private readonly IInventoryService _inventoryService;

        public TimedHostedService(
            ILogger<TimedHostedService> logger,
            IInventoryService inventoryService)
        {
            _logger = logger;
            _inventoryService = inventoryService; /// Problem Child
        }
}

Solution

  • If you wish to use a scoped service you will need to create a scope yourself;

            private readonly IServiceProvider serviceProvider;
    
            public TimedHostedService(IServiceProvider serviceProvider)
            {
                this.serviceProvider = serviceProvider;
                //...
            }
    
            public async Task StartAsync(CancellationToken cancellationToken)
            {
                using (var scope = serviceProvider.CreateScope())
                {
                    var ... = scope.ServiceProvider.GetService<...>();
                    //...
                }
            }