Troubleshooting Dependency Injection Error in .NET 5 API Background Task

58 Views Asked by At

The primary goal is to reload user account data at regular 30-minute intervals within a .NET 5 API. In pursuit of this goal, I learned something about implementing background tasks to automate this process. Following a tutorial, I attempted to set up a background task, also having a scopedService. However, during the implementation, I encountered persistent errors:

1.

“No service for type ‘AccountRepository.AccountScopedService’ has been registered.”

Despite multiple troubleshooting attempts, including service registration checks, dependency injection verification, and rewatching the video, the error remains unresolved.

  1. If I undo the last step of the video and just use IAccountSingletonService singletonService, IAccountTransientService transientService in the ctor (that is, without IServiceProvider serviceProvider), the application freezes. Swagger is not loaded. busy

I appreciate your help.

AccountLoaderBackgroundService.cs

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace AccountRepository
{
    public class AccountLoaderBackgroundService : BackgroundService
    {
        public readonly List<Person> AllPersons = new List<Person>();
        private readonly IServiceProvider _serviceProvider;
        private readonly IAccountSingletonService singletonService;
        private readonly IAcountTransientService transientService;

        public AccountLoaderBackgroundService(IAccountSingletonService singletonService,
                                              IAcountTransientService transientService,
                                              IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                using (var scope = _serviceProvider.CreateScope())
                {
                    var scopedService = scope.ServiceProvider.GetRequiredService<AccountScopedService>();
                    LoadAccounts();
                    System.Diagnostics.Debug.WriteLine("ExecuteAsync in AccountLoaderBackgroundService");
                    await Task.Delay(new TimeSpan(0, 30, 0));
                }
            }
        }

        public bool LoadAccounts()
        {
            // reading data
            return true;
        }
    }
}

AccountLoaderHostedService.cs

using Microsoft.Extensions.Hosting;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace AccountRepository
{
    public class AccountLoaderHostedService : IHostedService
    {
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                System.Diagnostics.Debug.WriteLine("StartAsync in AccountLoaderHostedService");
                await Task.Delay(new TimeSpan(0, 30, 0));
            }
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }
    }
}

Startup.cs

services.AddSingleton<AccountRepository.IAccountSingletonService, AccountRepository.AccountSingletonService>();
services.AddScoped<AccountRepository.IAccountScopedService, AccountRepository.AccountScopedService>();
services.AddTransient<AccountRepository.IAcountTransientService, AccountRepository.AcountTransientService>();
services.AddHostedService<AccountRepository.AccountLoaderBackgroundService>();
services.AddHostedService<AccountRepository.AccountLoaderHostedService>();

Plus, I wrote the classes and interfaces for the 3 services.

public class AccountScopedService : IAccountScopedService
    {
    }

public class AccountSingletonService : IAccountSingletonService
    {
    }

public class AcountTransientService : IAcountTransientService
    {
    }

public interface IAccountScopedService
    {
    }

public interface IAccountSingletonService
    {
    }

public interface IAcountTransientService
    {
    }
1

There are 1 best solutions below

2
Nico Volling On BEST ANSWER

It seems you're registering the interface IAccountScopedService in startup.cs on line 2, but you're requesting the concrete class AccountScopedService in AccountLoaderBackgroundService.cs on line 30. To fix this, you should request IAccountScopedService instead of AccountScopedService on line 30 in AccountLoaderBackgroundService.cs.

Hope it helps. If you have any questions, don't hesitate to contact me.

Kind regards Nico