简体   繁体   English

Quartz.net Core 中的依赖注入找不到已注册的服务

[英]Dependency injection in Quartz.net Core not finding registered services

I am getting a DI registration issue when trying to setup Quartz, the job is a simple test job to confirm DI is working (that just outputs text to the console).我在尝试设置 Quartz 时遇到 DI 注册问题,该作业是一个简单的测试作业,用于确认 DI 是否正常工作(仅将文本输出到控制台)。

The code where the error is thrown is in the last class JobFactory .抛出错误的代码在最后一个类JobFactory

Program.cs程序.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);
    }
}

Setup the Quartz job factory:设置 Quartz 作业工厂:

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;
}

Background worker:后台工作者:

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.");
    }
}

Job factory (where the error occurs):作业工厂(发生错误的地方):

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();
        }
    }
}

Runtime error:运行时错误:

System.InvalidOperationException: 'No service for type 'xxx.yyy.SomeJob' has been registered.' System.InvalidOperationException: '没有注册 'xxx.yyy.SomeJob' 类型的服务。

The background worker is being given a provider before all the required dependencies are added.在添加所有必需的依赖项之前,后台工作人员会获得一个提供程序。

//...

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()

//...

Once a service collection is built, any changes (additions/removal) from the collection have no effect on an already built provider.构建服务集合后,集合中的任何更改(添加/删除)都不会影响已构建的提供程序。

Consider changing approach and using a deferred delegate factory when registering the worker在注册工人时考虑改变方法并使用延迟委托工厂

//...

services.AddSingleton<IHostedService>(serviceProvider => new BackgroundWorker(serviceProvider));

//...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM