Как интегрировать задания Quartz.Net, для которых требуются «ограниченные» сервисы (ASP.NET Core 2.0)? - PullRequest
0 голосов
/ 14 марта 2019

Я пытаюсь создать несколько рабочих мест Quartz.Net после моего собственного ответа из этого вопроса . Однако, если задание является довольно сложным и требует "ограниченных" (services.AddScoped<.., ...>) служб, пример не работает, поскольку задания создаются как одиночные.

Если я изменю их, чтобы охватить, serviceProvider не будет содержать нужные мне услуги. Мне удалось заставить его работать, используя следующий код:

Startup.cs

/// <summary>
/// service provider to be used by qiaryz job factory which cannot use its default provider
/// since child services are scoped and the jobs are singleton
/// </summary>
public static IServiceProvider QuartzScopedProvider { get; private set; }

private void ConfigureQuartz(IServiceCollection services, params Type[] jobs)
{
    services.AddSingleton<IJobFactory, QuartzJobFactory>();
    services.Add(jobs.Select(jobType => new ServiceDescriptor(jobType, jobType, ServiceLifetime.Singleton)));

    QuartzScopedProvider = services.BuildServiceProvider();

    services.AddSingleton(provider =>
    {
        var schedulerFactory = new StdSchedulerFactory();
        var scheduler = schedulerFactory.GetScheduler().Result;
        scheduler.JobFactory = provider.GetService<IJobFactory>();
        scheduler.Start();
        return scheduler;
    });
}

/// <summary>
/// configures quartz services
/// </summary>
/// <param name="services"></param>
protected virtual void ConfigureJobsIoc(IServiceCollection services)
{
    // all custom services are already defined at this point

    ConfigureQuartz(services, typeof(ComplexJob));
}

/// <summary>
/// configures and starts async jobs (Quartz)
/// </summary>
/// <param name="app"></param>
/// <param name="lifetime"></param>
protected virtual void StartJobs(IApplicationBuilder app, IApplicationLifetime lifetime)
{
    var scheduler = app.ApplicationServices.GetService<IScheduler>();

    QuartzServicesUtilities.StartJob<ComplexJob>(scheduler, TimeSpan.FromMinutes(60));

    lifetime.ApplicationStarted.Register(() => scheduler.Start());
    lifetime.ApplicationStopping.Register(() => scheduler.Shutdown(waitForJobsToComplete: true));
}

QuartzJobFactory.cs

Фабрика заданий не использует внедренный поставщик услуг, но тот, который явно создан в Startup.cs

public class QuartzJobFactory : IJobFactory
{
    private readonly IServiceProvider _serviceProvider;

    /// <inheritdoc/>
    public QuartzJobFactory()
    {
        // _serviceProvider = serviceProvider;
        _serviceProvider = Startup.QuartzScopedProvider;
    }

    /// <inheritdoc/>
    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    {
        var jobDetail = bundle.JobDetail;

        // this fails with injected service provider:
        // 1: cannot inject scoped services in singleton service
        // 2: if jobs are scoped, the provider cannot solve the injected services
        var job = (IJob)_serviceProvider.GetService(jobDetail.JobType);
        return job;
    }

    /// <inheritdoc/>
    public void ReturnJob(IJob job) { }
}

Мне интересно, является ли это хорошим способом работы с заданиями Quartz в ASP.NET Core 2.0, потому что это больше похоже на взлом, чем на реальное решение.

Вопрос: Как интегрировать задания Quartz.Net, для которых требуются «ограниченные» сервисы (ASP.NET Core 2.0)?

1 Ответ

1 голос
/ 15 марта 2019

Для восстановления службы из области * из IServiceProvider, попробуйте

    using (var scope = _serviceProvider.CreateScope())
    {
        var job = (IJob)scope.ServiceProvider.GetService(jobDetail.JobType);            
    }
...