1

我正在使用 .NET 5,我想使用IHostedServiceclassess 运行后台任务,如您所见:

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
}

所以我必须将它注入到服务集合中,如您所见:

services.AddHostedService<PasargadJobs>();

但是在添加这个之后我得到了这个错误:

System.AggregateException:'某些服务无法构造(验证服务描述符时出错'ServiceType:Microsoft.Extensions.Hosting.IHostedService Lifetime:Singleton ImplementationType:MIMS.Portal.ScheduleJobs.PasargadJobs':无法使用范围服务'Microsoft .EntityFrameworkCore.DbContextOptions`1[MIMS.Portal.Infrustructure.Repositories.AppDbContext]' 来自单例'Microsoft.Extensions.Hosting.IHostedService'。)'

这是我的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>();
4

1 回答 1

2

您的托管服务是单例的,并且您间接依赖于范围服务:

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

您可以通过以下方式解决问题

注入IServiceScopeFactory您的托管服务并手动创建服务范围,如下所示

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

不要将CreateScopeandGetRequiredService放在托管服务的构造函数中:由于托管服务是单例的,构造函数只会被调用一次,因此创建的实例scope.ServiceProvider.GetRequiredService<T>()也将被创建一次。因此,在这种情况下,您将使用被设计为短暂存在的服务作为永远活着的单身人士。使用后也不要忘记丢弃scope

由于看起来您正在使用 Entity Framework Core 和上述方法的替代方案,您还可以考虑重构要使用的服务,IDbContextFactory<TContext> 以便将它们注册为单例服务。

于 2022-02-19T21:34:00.257 回答