'Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType:IHostedService
J

2

16

I am using .NET 5 and I want to run a background task using IHostedService classess as you can see:

public class PasargadJobs : IHostedService, IDisposable
{
    private Timer _timer = null!;
    readonly  ITerminalService _terminalService;
    readonly  IMessageService _messageService;
    readonly IMerchantService _merchantService;
    
    public PasargadJobs(
        IMerchantService merchantService,
        ITerminalService terminalService,
        IMessageService messageService)
    {
        _messageService = messageService;
        _terminalService = terminalService;
        _merchantService = merchantService;
    }
    
    //other parts of code are removed for short code
}

So I have to inject it to service collection as you can see :

services.AddHostedService<PasargadJobs>();

But after adding this I got this error :

System.AggregateException: 'Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: Microsoft.Extensions.Hosting.IHostedService Lifetime: Singleton ImplementationType: MIMS.Portal.ScheduleJobs.PasargadJobs': Cannot consume scoped service 'Microsoft.EntityFrameworkCore.DbContextOptions`1[MIMS.Portal.Infrustructure.Repositories.AppDbContext]' from singleton 'Microsoft.Extensions.Hosting.IHostedService'.)'

Here is my startup.cs

services.AddExpressiveAnnotations();

//--- DB Context ---//
services.AddTransient<AppDbContext, AppDbContext>();
//--- Repositories ---//
services.AddTransient(typeof(IGenericRepository<>), typeof(GenericRepository<>));
services.AddTransient<IMerchantRepository, MerchantRepository>();
services.AddTransient<IBankAccountRepository, BankAccountRepository>();
services.AddTransient<IBankRepository, BankRepository>();
services.AddTransient<IGeoRepository, GeoRepository>();
services.AddTransient<IDepartmentRepository, DepartmentRepository>();
services.AddTransient<IDeviceRepository, DeviceRepository>();
services.AddTransient<IInvoiceRepository, InvoiceRepository>();
services.AddTransient<IStoreRepository, StoreRepository>();
services.AddTransient<ITerminalRepository, TerminalRepository>();
services.AddTransient<ITicketRepository, TicketRepository>();
services.AddTransient<IUserRepository, UserRepository>();
services.AddTransient<IFileRepository, FileRepository>();
services.AddTransient<IPartnerRepository, PartnerRepository>();
services.AddTransient<IStoreScopeRepository, StoreScopeRepository>();
services.AddTransient<ICommentRepository, CommentRepository>();
services.AddTransient<INewsRepository, NewsRepository>();
services.AddTransient<IPosBrandRepository, PosBrandRepository>();
//-- Services --//
services.AddTransient<IMerchantService, MerchantService>();
services.AddTransient<IBankAccountService, BankAccountService>();
services.AddTransient<IBankService, BankService>();
services.AddTransient<IGeoService, GeoService>();
services.AddTransient<IDepartmentService, DepartmentService>();
services.AddTransient<IDeviceService, DeviceService>();
services.AddTransient<IInvoiceService, InvoiceService>();
services.AddTransient<IStoreService, StoreService>();
services.AddTransient<ITerminalService, TerminalService>();
services.AddTransient<ITicketService, TicketService>();
services.AddTransient<IUsersService, UsersService>();
services.AddTransient<IFilesManagerService, FilesManagerService>();
services.AddTransient<IMessageService, MessageService>();
services.AddTransient<IPartnerService, PartnerService>();
services.AddTransient<IStoreScopeService, StoreScopeService>();
services.AddTransient<INewsService, NewsService>();
services.AddTransient<ICommentService, CommentService>();
services.AddTransient<IPosBrandService, PosBrandService>();

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

services
    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(option =>
    {
        option.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = "localhost",
            ValidAudience = "localhost",
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes("wevhgfrtyhasdfghjklzxcvbnm"))
        };
    });
    
services.AddHostedService<PasargadJobs>();
Jolynnjon answered 19/2, 2022 at 21:5 Comment(0)
T
26

Your hosted service is singleton and you have an indirect dependency to a scoped service:

Cannot consume scoped service 'Microsoft.EntityFrameworkCore.DbContextOptions`1[MIMS.Portal.Infrustructure.Repositories.AppDbContext]' from singleton 'Microsoft.Extensions.Hosting.IHostedService'

You can workaround the problem in the following ways

Inject IServiceScopeFactory into your hosted service and create the service scope manually like below

using var scope = _serviceScopeFactory.CreateScope();
var service = scope.ServiceProvider.GetRequiredService<IScopedService>();

Do not put the CreateScope and GetRequiredService in the constructor of the hosted service: Since the hosted service is a singleton, the constructor will be called only once and hence instances created by scope.ServiceProvider.GetRequiredService<T>() will also be created once. So in this case you would use services that are designed to be short-lived as forever living singletons. Also do not forget to dispose scope after usage.

Since it looks like you are using Entity Framework Core and alternative to the approach above you could also consider to refactor your services to use IDbContextFactory<TContext> so they can be registered as singelton services.

Traffic answered 19/2, 2022 at 21:34 Comment(6)
Thanks .I have changed the class : readonly IServiceScopeFactory _serviceScopeFactory; public PasargadJobs(IServiceScopeFactory serviceScopeFactory) { _serviceScopeFactory = serviceScopeFactory; var scope = _serviceScopeFactory.CreateScope(); var _terminalService = scope.ServiceProvider.GetRequiredService<ITerminalService>(); var _merchantService = scope.ServiceProvider.GetRequiredService<IMerchantService>(); var _messageService = scope.ServiceProvider.GetRequiredService<IMessageService>(); }Jolynnjon
But the terminalService and merchandService and messageService asre null why ?Jolynnjon
I can spot two issues: First: looks like you are assigning the services to local variables instead of fields: var _terminalService = ... instead of _terminalService = ... like this you assign the service to a local variable and the field _terminalService remains null. Also do not create the services in the constructor, this will basically make all services singletons.Traffic
Thanks ,it worked .I moved them from constructor into my method and it works .Jolynnjon
Do I really need to dispose the scope? You're using using, which will dispose that for me automagically at the end of the scope, anyway. Do I miss something?Siddon
using in the sample is enough. I just waned to highlight that is important to dispose scopes in some way.Traffic
B
-1

Implement a BackgroundService in your class. It already implements IHostedService and IDisposable

public class PasargadJobs : BackgroundService

services.AddHostedService<PasargadJobs>();
Berenice answered 30/3, 2022 at 23:26 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Autocrat

© 2022 - 2024 — McMap. All rights reserved.