C# Quartz.net Core中的依赖项注入找不到已注册的服务
我在尝试设置Quartz时遇到DI注册问题,该作业是一个简单的测试作业,用于确认DI是否正常工作(仅将文本输出到控制台) 引发错误的代码位于最后一个类C# Quartz.net Core中的依赖项注入找不到已注册的服务,c#,dependency-injection,.net-core,quartz.net,C#,Dependency Injection,.net Core,Quartz.net,我在尝试设置Quartz时遇到DI注册问题,该作业是一个简单的测试作业,用于确认DI是否正常工作(仅将文本输出到控制台) 引发错误的代码位于最后一个类JobFactory中 Program.cs static async Task Main(string[] args) { var isService = !(Debugger.IsAttached || ((IList)args).Contains("--console")); var path = Path.GetDire
JobFactory
中
Program.cs
static async Task Main(string[] args)
{
var isService = !(Debugger.IsAttached || ((IList)args).Contains("--console"));
var path = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath);
var webHost = new HostBuilder()
.ConfigureAppConfiguration((cxt, config) =>
{
config.SetBasePath(path);
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
config.AddJsonFile($"appsettings.{environmentName}.json", optional: true, reloadOnChange: true);
config.AddEnvironmentVariables();
if (args != null)
{
config.AddCommandLine(args);
}
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(config.Build())
.Enrich.FromLogContext()
.CreateLogger();
})
.ConfigureServices((cxt, services) =>
{
var configuration = cxt.Configuration;
var bw = new BackgroundWorker(services.BuildServiceProvider());
services.AddSingleton<IHostedService>(bw);
services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true));
//services.AddSingleton<ISchedulerFactory, SchedulerFactory>();
//services.AddSingleton<ScopedJobFactory>();
services.AddScoped(_ => new SomeJob(configuration));
//services.AddTransient<IJob>(_ => new SomeJob(configuration));
var token = tokenSource.Token;
if (isService)
{
await webHost.RunAsServiceAsync(token);
}
else
{
await webHost.RunConsoleAsync(token);
}
}
作业工厂(发生错误的地方):
private static async Task<IScheduler> InitiateQuartzScheduler(IServiceProvider serviceProvider)
{
try
{
var factory = new StdSchedulerFactory();
var scheduler = await factory.GetScheduler();
scheduler.JobFactory = new JobFactory(serviceProvider);
await scheduler.Start();
return scheduler;
}
catch (SchedulerException se)
{
Log.Logger.Fatal(se, "Error at starting the Quartz Scheduler");
}
return null;
}
private class BackgroundWorker : IHostedService
{
private IScheduler quartzScheduler;
private readonly IServiceProvider serviceProvider;
public BackgroundWorker(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
//Log.Logger = SetupSerilog();
Log.Logger.Information("Starting Quartz BackgroundWorker.");
quartzScheduler = await InitiateQuartzScheduler(serviceProvider);
}
public async Task StopAsync(CancellationToken cancellationToken)
{
Log.Logger.Information("Quartz Background Worker is stopping.");
}
}
internal class JobFactory : IJobFactory
{
protected readonly IServiceProvider serviceProvider;
protected readonly ConcurrentDictionary<IJob, IServiceScope> _scopes = new ConcurrentDictionary<IJob, IServiceScope>();
public JobFactory(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
var scope = serviceProvider.CreateScope();
IJob job;
try
{
//
// **ERROR HERE**
//
job = scope.ServiceProvider.GetRequiredService(bundle.JobDetail.JobType) as IJob;
}
catch
{
// Failed to create the job -> ensure scope gets disposed
scope.Dispose();
throw;
}
// Add scope to dictionary so we can dispose it once the job finishes
if (!_scopes.TryAdd(job, scope))
{
// Failed to track DI scope -> ensure scope gets disposed
scope.Dispose();
throw new Exception("Failed to track DI scope");
}
return job;
}
public void ReturnJob(IJob job)
{
if (_scopes.TryRemove(job, out var scope))
{
// The Dispose() method ends the scope lifetime.
// Once Dispose is called, any scoped services that have been resolved from ServiceProvider will be disposed.
scope.Dispose();
}
}
}
内部类JobFactory:IJobFactory
{
受保护的只读IServiceProvider服务提供商;
受保护的只读ConcurrentDictionary _scopes=新ConcurrentDictionary();
公共工作工厂(IServiceProvider服务提供商)
{
this.serviceProvider=serviceProvider;
}
公共IJob NewJob(TriggerFiredBundle包,IScheduler调度器)
{
var scope=serviceProvider.CreateScope();
IJob工作;
尝试
{
//
//**此处有错误**
//
job=scope.ServiceProvider.GetRequiredService(bundle.JobDetail.JobType)作为IJob;
}
抓住
{
//未能创建作业->确保处理范围
scope.Dispose();
投掷;
}
//将作用域添加到字典中,以便在作业完成后处理它
if(!\u scopes.TryAdd(作业、范围))
{
//无法跟踪DI作用域->确保作用域被释放
scope.Dispose();
抛出新异常(“未能跟踪DI范围”);
}
返回工作;
}
公共作业(IJob作业)
{
if(_scopes.TryRemove(作业,超出变量范围))
{
//Dispose()方法结束作用域生存期。
//调用Dispose后,将处理从ServiceProvider解析的任何作用域服务。
scope.Dispose();
}
}
}
运行时错误:
System.InvalidOperationException:'没有类型的服务
已注册“xxx.yyy.SomeJob”
在添加所有必需的依赖项之前,后台工作程序将获得一个提供程序
//...
var configuration = cxt.Configuration;
var bw = new BackgroundWorker(services.BuildServiceProvider()); //<---This service provider
services.AddSingleton<IHostedService>(bw);
services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true));
services.AddScoped(_ => new SomeJob(configuration)); //<--knows nothing about this service
//...or any other service added after services.BuildServiceProvider()
//...
/。。。
var配置=cxt.配置;
var bw=新的BackgroundWorker(services.BuildServiceProvider());//loggingBuilder.AddSerilog(dispose:true));
services.AddScoped(=>newsomejob(配置));//新的后台工作人员(服务提供商);
//...
什么是bundle.JobDetail.JobType
?您的DI容器中是否设置了相应的类型?@DavidGbundle.JobDetail.JobType
是石英触发器,传入的作业,具体来说,JopType
是作业的类型,例如SomeJob
(从`ConfigureServices
部分。在添加所有必需的依赖项之前,后台工作程序将获得一个提供程序。一旦构建了服务集合,任何更改(添加/删除)都将被删除对已生成的提供程序没有影响。@Nkosi您是100%正确的!谢谢,请提供答案,以便我可以将其标记为已接受。
//...
services.AddSingleton<IHostedService>(serviceProvider => new BackgroundWorker(serviceProvider));
//...