MaterializationInterceptors引发EF创建过多IServiceProvider实例问题
问题根源
你直接实例化UserFactoryInterceptor作为拦截器添加到DbContext,这会导致拦截器成为单例(DbContext的DI注册阶段完成时,实例化的拦截器会被长期持有)。而EF Core的规则是:单例拦截器如果依赖Scoped/Transient服务,或者被多个Scoped的DbContext实例引用,会不断创建新的IServiceProvider来隔离服务,当数量超过默认阈值(20)时就会抛出该异常。
解决方案
1. 让拦截器通过DI获取,禁止直接实例化
把UserFactoryInterceptor注册为Scoped服务,在DbContext配置时通过服务提供者获取它,而非直接new。
修改DI配置代码:
// 注册Scoped的IUserFactory services.AddScoped<IUserFactory, UserFactory>(); // 将拦截器注册为Scoped服务 services.AddScoped<UserFactoryInterceptor>(); // 配置DbContext时,通过IServiceProvider获取拦截器实例 services.AddDbContext<YourDbContext>((sp, options) => { var interceptor = sp.GetRequiredService<UserFactoryInterceptor>(); options.AddInterceptors(interceptor); // 补充你的DbContext其他配置,比如连接字符串 });
2. 调整拦截器的服务注入方式
在UserFactoryInterceptor中,直接通过构造函数注入IUserFactory即可(因为拦截器现在是Scoped,和DbContext同生命周期),无需从DbContext上下文获取。
修改UserFactoryInterceptor:
public class UserFactoryInterceptor : IMaterializationInterceptor { private readonly IUserFactory _userFactory; // 直接注入同生命周期的IUserFactory public UserFactoryInterceptor(IUserFactory userFactory) { _userFactory = userFactory; } public object Initialized(MaterializationInterceptionData materializationData, object instance) { if (instance is Workgroup workgroup) { workgroup.UserFactory = _userFactory; } return instance; } }
3. 确认生命周期匹配
确保以下组件的生命周期一致:
IUserFactory:ScopedUserFactoryInterceptor:ScopedYourDbContext:Scoped(默认注册方式就是Scoped)
这样每次请求中创建的DbContext、拦截器、IUserFactory都属于同一生命周期实例,不会触发EF重复创建IServiceProvider的问题。
补充说明
如果你的UserFactory确实需要依赖DbContext,当前配置也能正常工作——因为Scoped的UserFactory和DbContext同属一个请求生命周期,可直接注入:
public class UserFactory : IUserFactory { private readonly YourDbContext _dbContext; public UserFactory(YourDbContext dbContext) { _dbContext = dbContext; } // 实现IUserFactory的业务方法 }
内容的提问来源于stack exchange,提问作者RezaNoei
相关产品推荐
相关产品推荐

