搭配DbContextFactory使用时无法从根提供者解析DbContext的Scoped服务
错误原因
调用CreateDbContext()无参重载时,IDbContextFactory默认会使用初始化阶段绑定的根服务提供者解析DbContext的依赖项。Scoped服务仅能在对应的子作用域内完成解析,根提供者无法直接获取Scoped生命周期的ICurrentUserService,因此抛出对应错误。即使你将DbContext本身注册为Scoped,只要创建阶段的依赖解析走根容器,就会触发该问题,和DbContext本身的注册生命周期无关。
解决方案
方案1(推荐):创建DbContext时传入当前作用域的服务提供者
修改你手写的Scoped DbContext注册逻辑,调用CreateDbContext时将当前作用域的provider作为参数传入,让依赖解析完全走当前请求的子作用域:
services.AddScoped<IMyDbContext>(provider => provider.GetRequiredService<IDbContextFactory<MyDbContext>>().CreateDbContext(provider)); services.AddScoped<MyDbContext>(provider => provider.GetRequiredService<IDbContextFactory<MyDbContext>>().CreateDbContext(provider));
该方案改动最小,不需要调整任何服务的生命周期,也不影响后台任务等无HttpContext场景下对IDbContextFactory的原生使用。
方案2:调整DbContextFactory的生命周期为Scoped
如果你使用.NET 6及以上版本,可以在注册工厂时直接将工厂本身注册为Scoped,和请求生命周期绑定,创建DbContext时会自动走当前作用域解析依赖:
services.AddDbContextFactory<MyDbContext>(options => options.UseSqlServer(config.ConnectionStrings.MSSQLConnection, x => { x.MigrationsHistoryTable("..."); x.MigrationsAssembly("..."); }), ServiceLifetime.Scoped, enableScopeValidation: true);
注意该方案下你无法在根作用域(比如后台任务、单例服务)中直接注入使用IDbContextFactory,如果有这类需求不要使用该方案。
注意事项
如果你的CurrentUserService内部依赖IHttpContextAccessor获取当前请求上下文,需要额外注册该服务:
services.AddHttpContextAccessor();
内容的提问来源于stack exchange,提问作者Matthias
相关产品推荐
相关产品推荐

