我没有太多使用依赖注入的经验,但是我试图在我的一个项目中使用它。当我尝试向我的构造函数中添加第二个参数时,出现错误“无法从单例中使用作用域服务'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)
{
...
}
}
答案 0 :(得分:1)
IHostedService
被注册为单例。您正在将ICarbonService
注入到ValidUntilTimerService
中,这意味着您正在将范围服务注入到单例服务中。
如果我们考虑这两种服务的寿命:
范围服务。这意味着,在实例化作用域服务时,该服务将保持活动状态,直到请求结束。
实例化单例服务后,该服务将保持活动状态,直到应用程序关闭。
我们意识到,从单例服务中使用作用域服务没有多大意义。在那种情况下会发生这种情况:
实例化单例服务(在您的情况下为ValidUntilTimerService
)时,其实例化的依赖项(在您的情况下为ICarbonService
)也被实例化并注入到单例服务中。请求完成后,单例服务保持活动状态,但作用域服务被处置。现在,您的单例服务最终以“无效”依赖项(在您的案例中为_carbonService
字段)。
以上情况是不可能的。这只是一个“假设”场景。关键是,您不能使用根据请求创建的服务,而无需请求即可创建服务(例如,在应用启动时)。
现在,这说明了问题的原因,但让我们看看如何解决该问题。
可能的解决方案
您可以使用IServiceScopeFactory在ValidUntilTimerService
内创建自己的范围:
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));
// ...
}
// ...
}