【问题标题】:C# Dependency Injection Cannot Consume Scoped?C#依赖注入不能使用Scoped?
【发布时间】:2019-03-26 22:07:40
【问题描述】:

我没有太多使用依赖注入的经验,但我正在尝试在我的一个项目中使用它。当我尝试向我的构造函数添加第二个参数时,我收到一个错误“无法从单例中使用范围服务'CarbonService'......”不知道为什么我会收到此错误或我缺少什么。感谢您的帮助

我希望我的计时器类能够访问 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)
  {
    ...
  }
}

【问题讨论】:

标签: c# dependency-injection


【解决方案1】:

IHostedServices 被注册为单例。您将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));
    // ...
  }
  // ...
}

【讨论】:

  • 感谢您的解释。这是有道理的。我提出了你的建议,一切都奏效了。问题,为什么不改变“services.AddSingleton();”仅供参考,它没有。我试过了
猜你喜欢
  • 2013-06-19
  • 1970-01-01
  • 2011-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-14
  • 2013-05-27
  • 2010-12-26
相关资源
最近更新 更多