.NET Core新手求助:服务层注入ApplicationDBContext失败问题
这问题我之前也踩过坑,核心原因是服务生命周期不匹配导致的,咱们一步步拆解解决:
问题根源
你把ApplicationEventService注册成了AddSingleton(全局单例生命周期),但它依赖的IApplicationEventHandler<T>是AddScoped(请求域生命周期)。.NET Core的DI容器有个严格规则:生命周期更长的服务不能直接依赖生命周期更短的服务——Singleton服务一旦创建就会一直存在于应用生命周期中,而Scoped服务是每个请求创建一次,Singleton没法拿到正确的Scoped实例,所以容器直接抛出了解析异常。
解决方案
方案一:调整ApplicationEventService的生命周期为Scoped(推荐)
既然你的事件触发是在请求过程中(AccountController的登录逻辑里),把事件服务改成Scoped完全合理,和依赖的Scoped服务生命周期对齐即可:
// 把原来的AddSingleton改成AddScoped services.AddScoped<IApplicationEventService, ApplicationEventService>();
这样修改后,每次请求都会创建一个新的ApplicationEventService实例,它能正常解析到同请求域内的Scoped事件处理程序和ApplicationDbContext。
方案二:如果必须保留Singleton,用IServiceScopeFactory创建作用域
如果因为某些特殊需求,必须让ApplicationEventService保持Singleton,那不能直接用根容器的IServiceProvider去解析Scoped服务,得通过IServiceScopeFactory手动创建作用域:
- 修改
ApplicationEventService的构造函数,注入IServiceScopeFactory而非IServiceProvider:
public class ApplicationEventService : IApplicationEventService { private readonly IServiceScopeFactory _scopeFactory; public ApplicationEventService(IServiceScopeFactory scopeFactory) { _scopeFactory = scopeFactory; } public async Task Raise<T>(T eventObj) where T : IApplicationEvent { // 创建一个新的作用域 using var scope = _scopeFactory.CreateScope(); // 在新作用域内获取事件处理程序 var handlers = scope.ServiceProvider.GetServices<IApplicationEventHandler<T>>(); foreach (var handler in handlers) { await handler.Handle(eventObj); } } }
- 保持
ApplicationEventService的Singleton注册不变:
services.AddSingleton<IApplicationEventService, ApplicationEventService>();
这种方式下,每次触发事件时都会创建一个独立的作用域,确保能正确获取到Scoped的LoginHistoryService和ApplicationDbContext实例。
额外提示
你的LoginHistoryService依赖ApplicationDbContext(默认是Scoped生命周期),所以它注册成AddScoped是完全正确的,不需要修改。
内容的提问来源于stack exchange,提问作者mmarjeh

