C#依赖注入无法使用范围吗?

时间:2019-03-26 22:07:40

标签: c# dependency-injection

我没有太多使用依赖注入的经验,但是我试图在我的一个项目中使用它。当我尝试向我的构造函数中添加第二个参数时,出现错误“无法从单例中使用作用域服务'CarbonService'...”。不确定为什么会收到此错误或丢失了什么。谢谢您的帮助

enter image description here

我希望我的计时器类可以访问CarbonService对象。

Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
  services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
  services.AddDbContext<CarbonDBContext>(o => o.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
  services.AddHostedService<ValidUntilTimerService>();
  services.AddScoped<ICarbonService, CarbonService>();  // I HAVE TRIED USING SINGLETON BUT SAME ERROR 

  services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true));
}

ValidUntilTimerService.cs:

// ADDING THE SECOND PARAMETER TO THIS CONSTRUCTOR CAUSES THE ERROR.
public class ValidUntilTimerService : IHostedService, IDisposable
{
  private readonly ILogger _logger;
  private Timer _timer;
  private ICarbonService _carbonService;

  public ValidUntilTimerService(ILogger<ValidUntilTimerService> logger, ICarbonService carbonService)
  {
    _logger = logger;
    _carbonService = carbonService; 
  }
  ...
}

CarbonService.cs:

public interface ICarbonService
{
  WattTime ReadCarbon();
  void SaveCarbon(int carbonIndex);
}

public class CarbonService : ICarbonService
{
  private IConfiguration _configuration;
  private readonly CarbonDBContext _dbcontext;

  public CarbonService(IConfiguration configuration, CarbonDBContext dbContext)
  {
    _configuration = configuration;
    _dbcontext = dbContext;
  }

  public WattTime ReadCarbon()
  {
    var wt = new WattTime();
    ...
    return wt;
  }

  public void SaveCarbon(int carbonIndex)
  {
    ...
  }
}

1 个答案:

答案 0 :(得分:1)

IHostedService被注册为单例。您正在将ICarbonService注入到ValidUntilTimerService中,这意味着您正在将范围服务注入到单例服务中。

如果我们考虑这两种服务的寿命:

    每个请求一次创建
  • 范围服务。这意味着,在实例化作用域服务时,该服务将保持活动状态,直到请求结束。

  • 实例化单例服务后,该服务将保持活动状态,直到应用程序关闭。

我们意识到,从单例服务中使用作用域服务没有多大意义。在那种情况下会发生这种情况:

实例化单例服务(在您的情况下为ValidUntilTimerService)时,其实例化的依赖项(在您的情况下为ICarbonService)也被实例化并注入到单例服务中。请求完成后,单例服务保持活动状态,但作用域服务被处置。现在,您的单例服务最终以“无效”依赖项(在您的案例中为_carbonService字段)。

以上情况是不可能的。这只是一个“假设”场景。关键是,您不能使用根据请求创建的服务,而无需请求即可创建服务(例如,在应用启动时)。

现在,这说明了问题的原因,但让我们看看如何解决该问题。

可能的解决方案

您可以使用IServiceScopeFactoryValidUntilTimerService内创建自己的范围:

public class ValidUntilTimerService : IHostedService, IDisposable
{
  private readonly ILogger _logger;
  private Timer _timer;
  private IServiceScopeFactory _serviceScopeFactory;

  public ValidUntilTimerService(ILogger<ValidUntilTimerService> logger, IServiceScopeFactory serviceScopeFactory)
  {
    _logger = logger;
    _serviceScopeFactory = serviceScopeFactory; 
  }

  // ...
  using (var scope = _serviceScopeFactory.CreateScope())
  {
     ICarbonService carbonService = scope.ServiceProvider.GetService(typeof(ICarbonService));
    // ...
  }
  // ...
}