You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 16:03:10