ASP.NET Core中通过DI在运行时注册服务遇错误求助
问题分析
你遇到的错误No service for type IRunTransaction has been registered.(翻译:未注册IRunTransaction类型的服务),核心原因是:你正在使用的_serviceProvider是在调用_serviceCollection.AddTransient<IRunTransaction, AddPosition>()之前就已经构建完成的。.NET的DI容器中,一旦ServiceProvider被构建,后续对ServiceCollection的修改不会同步到已存在的ServiceProvider实例中,所以新注册的服务在旧容器里找不到。
解决方案
下面提供几种可行的解决思路:
思路1:重新构建ServiceProvider(不推荐频繁使用)
如果必须动态注册服务后立即使用,可以基于更新后的ServiceCollection重新构建一个新的ServiceProvider,再用它创建作用域:
public async Task<object?> AddPositionToDb() { var position = new ModelPosition { EmployeeNumber = "01234", PositionEmploymentStatus = "01", PositionNumber = "123", PositionStart = DateTime.Now, PositionEnd = DateTime.Now.AddYears(6) }; // 注册服务 _serviceCollection.AddTransient<IRunTransaction, AddPosition>(); // 基于更新后的服务集合构建新的ServiceProvider var newServiceProvider = _serviceCollection.BuildServiceProvider(); using (IServiceScope scope = newServiceProvider.CreateScope()) { var transService = scope.ServiceProvider.GetRequiredService<IRunTransaction>(); await transService.RunTransaction(position); // 注意加上await return response; } }
⚠️ 注意:频繁构建ServiceProvider会增加资源开销,不适合高频场景。
思路2:使用工厂模式提前注册(推荐)
提前在DI容器中注册一个工厂,运行时直接通过工厂创建实例,无需动态修改服务集合:
// 提前在启动时注册工厂(比如Program.cs里) _serviceCollection.AddTransient<Func<Type, IRunTransaction>>(sp => type => { return (IRunTransaction)ActivatorUtilities.CreateInstance(sp, type); }); // 业务方法中使用 public async Task<object?> AddPositionToDb() { var position = new ModelPosition { EmployeeNumber = "01234", PositionEmploymentStatus = "01", PositionNumber = "123", PositionStart = DateTime.Now, PositionEnd = DateTime.Now.AddYears(6) }; // 直接通过工厂创建实例,无需动态注册 using (IServiceScope scope = _serviceProvider.CreateScope()) { var factory = scope.ServiceProvider.GetRequiredService<Func<Type, IRunTransaction>>(); var transService = factory(typeof(AddPosition)); await transService.RunTransaction(position); return response; } }
这种方式无需修改已构建的容器,更符合DI的设计原则,性能也更稳定。
思路3:直接创建实例(简单场景适用)
如果AddPosition不需要依赖其他服务,直接手动创建实例即可,完全绕开DI注册的步骤:
public async Task<object?> AddPositionToDb() { var position = new ModelPosition { EmployeeNumber = "01234", PositionEmploymentStatus = "01", PositionNumber = "123", PositionStart = DateTime.Now, PositionEnd = DateTime.Now.AddYears(6) }; var transService = new AddPosition(); await transService.RunTransaction(position); return response; }
另外,你的代码里还有两个小问题需要修正:
AddPosition中的RunTransaction方法需要加上public修饰符,否则无法实现接口的公开方法- 调用
RunTransaction时要加上await,确保异步任务执行完成
内容的提问来源于stack exchange,提问作者Sonam Mohite
相关产品推荐
相关产品推荐

