'某些服务无法构建(验证服务描述符时出错'ServiceType:IHostedService
'Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType:IHostedService
我正在使用 .NET 5,我想 运行 使用 IHostedService
类的后台任务,如您所见:
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: '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'.)'
这是我的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>();
您的托管服务是单例的,并且您间接依赖于作用域服务:
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>();
不要将 CreateScope
和 GetRequiredService
放在托管服务的构造函数中:由于托管服务是单例的,构造函数将只被调用一次,因此实例由 scope.ServiceProvider.GetRequiredService<T>()
也会创建一次。因此,在这种情况下,您将使用设计为 short-lived 的服务作为永远活着的单身人士。也不要忘记在使用后处理 scope
。
因为看起来您正在使用 Entity Framework 核心和上述方法的替代方法,您还可以考虑重构您的服务以使用 IDbContextFactory<TContext>
以便它们可以注册为单一服务。
在您的 class 中实施 BackgroundService
。它已经实现了 IHostedService
和 IDisposable
public class PasargadJobs : BackgroundService
services.AddHostedService<PasargadJobs>();
我正在使用 .NET 5,我想 运行 使用 IHostedService
类的后台任务,如您所见:
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: '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'.)'
这是我的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>();
您的托管服务是单例的,并且您间接依赖于作用域服务:
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>();
不要将 CreateScope
和 GetRequiredService
放在托管服务的构造函数中:由于托管服务是单例的,构造函数将只被调用一次,因此实例由 scope.ServiceProvider.GetRequiredService<T>()
也会创建一次。因此,在这种情况下,您将使用设计为 short-lived 的服务作为永远活着的单身人士。也不要忘记在使用后处理 scope
。
因为看起来您正在使用 Entity Framework 核心和上述方法的替代方法,您还可以考虑重构您的服务以使用 IDbContextFactory<TContext>
以便它们可以注册为单一服务。
在您的 class 中实施 BackgroundService
。它已经实现了 IHostedService
和 IDisposable
public class PasargadJobs : BackgroundService
services.AddHostedService<PasargadJobs>();