web-dev-qa-db-fra.com

Injection de dépendance de quartz de base .net

Comment puis-je configurer Quartz dans . Net core pour utiliser l'injection de dépendance? J'utilise le mécanisme de dépendance standard .net core. Dans le constructeur de classe qui implémente IJob, j'ai besoin d'injecter quelques dépendances.

12
donex93

Vous pouvez utiliser le Quartz.Spi.IJobFactory interface et l'implémenter. Les documentations Quartz indiquent:

Lorsqu'un déclencheur se déclenche, le Job auquel il est associé est instancié via JobFactory configuré sur le Planificateur. La JobFactory par défaut active simplement une nouvelle instance de la classe d'emplois. Vous souhaiterez peut-être créer votre propre implémentation de JobFactory pour accomplir des tâches telles que faire en sorte que le conteneur IoC ou DI de votre application produise/initialise l'instance de travail. Voir l'interface IJobFactory et la méthode Scheduler.SetJobFactory (fact) associée.

ISchedulerFactory schedulerFactory = new StdSchedulerFactory(properties);
var scheduler = schedulerFactory.GetScheduler();

scheduler.JobFactory = jobFactory;

Modifier

L'implémentation peut ressembler à ceci:

public class JobFactory : IJobFactory
{
    protected readonly IServiceProvider Container;

    public JobFactory(IServiceProvider container)
    {
        Container = container;
    }

    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    {
        return Container.GetService(bundle.JobDetail.JobType) as IJob;
    }

    public void ReturnJob(IJob job)
    {
        // i couldn't find a way to release services with your preferred DI, 
        // its up to you to google such things
    }
}

Pour l'utiliser avec le Microsoft.Extensions.DependencyInjection créez votre conteneur comme ceci:

var services = new ServiceCollection();
services.AddTransient<IAuthorizable, AuthorizeService>();
var container = services.BuildServiceProvider();
var jobFactory = new JobFactory(container);

Références

  1. documentation Quartz

  2. Api

13
Rabban

Inspiré par grande réponse de Rabbans J'ai créé une implémentation complète d'une JobFactory pour Microsoft.Extensions.DependencyInjection:

La mise en oeuvre

using Microsoft.Extensions.DependencyInjection;
using Quartz;
using Quartz.Spi;
using System;
using System.Collections.Concurrent;

class JobFactory : IJobFactory
{
    protected readonly IServiceProvider _serviceProvider;

    protected readonly ConcurrentDictionary<IJob, IServiceScope> _scopes = new ConcurrentDictionary<IJob, IServiceScope>();

    public JobFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    {
        var scope = _serviceProvider.CreateScope();
        IJob job;

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

Usage

// Prepare the DI container
var services = new ServiceCollection();
// Register job
services.AddTransient<MyJob>();
// Register job dependencies
services.AddTransient<IFoo, Foo>();
var container = services.BuildServiceProvider();

// Create an instance of the job factory
var jobFactory = new JobFactory(container);

// Create a Quartz.NET scheduler
var schedulerFactory = new StdSchedulerFactory(properties);
var scheduler = schedulerFactory.GetScheduler();

// Tell the scheduler to use the custom job factory
scheduler.JobFactory = jobFactory;

L'implémentation a été testée dans une application console .NET Core 2.1 avec un seul travail et a bien fonctionné. N'hésitez pas à laisser vos commentaires ou suggestions d'amélioration ...

4
CodeZombie

Aucune idée si cela sera utile ou non, mais j'ai créé ma propre extension DI pour Quartz que vous êtes plus que bienvenu à essayer: https://github.com/JaronrH/Quartz.DependencyInjection

La version courte est que vous utiliseriez la méthode AddQuartz () pour passer la configuration [facultative] NaveValueCollection et l'assemblage Scrutor [requis] que vous recherchez (voir https://andrewlock.net/using-scrutor-to- enregistrer-automatiquement-vos-services-avec-le-conteneur-core-asp-net / ). Par exemple:

services.AddQuartz(s => s.FromAssemblyOf<Program>())

Cet appel:

  • Recherchez et enregistrez automatiquement toutes les implémentations IJob, IAddScheduledJob, IAddSchedulerListener, IAddTriggerListener et IAddJobListener trouvées dans les assemblys (Scrutor). Donc, oui, vous pouvez utiliser DI dans vos classes IJob de cette façon!
  • Configurez un IScheduler Singleton dans DI qui utilise les ressources DI ci-dessus.
  • Enregistrez un adaptateur dans l'IScheduler afin que la journalisation de Microsoft soit utilisée pour la journalisation de Quartz.

Vous pouvez ensuite utiliser provider.StartQuartz () pour démarrer le planificateur (qui recherche automatiquement IApplicationLifetime et enregistre le planificateur pour l'arrêt si disponible) ou utilisez DI conventionnel pour obtenir et démarrer les services (provider.GetService (). Start (); ).

J'espère que cela t'aides!

1
Jaron