.NET 8 Worker Service部分服务无法构造问题求助
问题分析与解决方案
核心问题
- 生命周期不匹配:
Worker作为托管服务默认是Singleton生命周期,而IUnitOfWork注册为Scoped生命周期。.NET DI禁止将短生命周期的Scoped服务注入到长生命周期的Singleton服务中,这是引发构造异常的主要原因。 - 提前构建ServiceProvider:
program.cs中提前调用BuildServiceProvider()创建了独立容器,与后续host.Build()生成的容器不一致,破坏了DI的正常注册流程。 - Worker构造函数冗余:存在无参构造函数可能导致DI容器优先选择它,使依赖服务无法正确注入;同时手动实例化
cMain,没有利用已注册的Singleton实例。
分步解决方案
1. 修复生命周期不匹配(推荐方案)
保留IUnitOfWork的Scoped生命周期,在Worker中通过IServiceScopeFactory动态创建Scoped实例:
public class Worker : BackgroundService { private readonly ILogger<Worker> _logger; private readonly IServiceScopeFactory _scopeFactory; private readonly cMain _cmain; // 移除无参构造函数,仅保留依赖注入的构造函数 public Worker(ILogger<Worker> logger, IServiceScopeFactory scopeFactory, cMain cmain) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _scopeFactory = scopeFactory ?? throw new ArgumentNullException(nameof(scopeFactory)); _cmain = cmain ?? throw new ArgumentNullException(nameof(cmain)); } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { // 每次业务逻辑执行时创建独立Scope using (var scope = _scopeFactory.CreateScope()) { var uow = scope.ServiceProvider.GetRequiredService<IUnitOfWork>(); var breadCrumb = new BreadCrumb { Application = Assembly.GetExecutingAssembly().GetName().Name, DateTime = DateTime.Now, Description = "Test", EnquiryHeader_ID = 1, EventName = "Test", ReferenceID = 1, Result = "Test" }; await uow.BreadCrumbs.AddAsync(breadCrumb); uow.Save(); } if (_logger.IsEnabled(LogLevel.Information)) { _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now); } await Task.Delay(1000, stoppingToken); } } }
2. 修复program.cs中的ServiceProvider问题
取消提前构建容器,在AddDbContext的配置委托中通过服务提供者获取cMain实例:
var builder = Host.CreateApplicationBuilder(args); builder.Services.AddSingleton<cMain>(); // 直接在DbContext配置中获取cMain,无需提前构建容器 builder.Services.AddDbContext<ApplicationDbContext>((sp, options) => { var cMainInstance = sp.GetRequiredService<cMain>(); options.UseSqlServer(cMainInstance.ConnectionString); }); builder.Services.AddScoped<IUnitOfWork, UnitOfWork>(); // 若BreadCrumbRepository需要依赖注入,需添加以下注册 // builder.Services.AddScoped<IBreadCrumbRepository, BreadCrumbRepository>(); builder.Services.AddHostedService<Worker>(); var host = builder.Build(); host.Run();
3. 额外检查
确保IBreadCrumbRepository的实现类已正确处理依赖:如果后续需要给BreadCrumbRepository注入其他服务,需将其注册到DI容器中;当前代码中直接在UnitOfWork里实例化的方式可正常运行,但灵活性较低。
内容的提问来源于stack exchange,提问作者simon westwood
相关产品推荐
相关产品推荐

