73 votes

Injection de dépendances Hangfire avec .NET Core

Comment puis-je utiliser l'injection de dépendances par défaut de .NET Core dans Hangfire ?

Je suis nouveau sur Hangfire et je cherche un exemple qui fonctionne avec ASP.NET Core.

69voto

Gonzalo Lucero Points 1081

Voir l'exemple complet sur GitHub https://github.com/gonzigonz/HangfireCore-Example .
Site en direct à http://hangfirecore.azurewebsites.net/

  1. Assurez-vous que vous avez la version Core de Hangfire :
    dotnet add package Hangfire.AspNetCore

  2. Configurez votre IoC en définissant un JobActivator . Voici la configuration à utiliser avec le service conteneur asp.net core par défaut :

    public class HangfireActivator : Hangfire.JobActivator
    {
        private readonly IServiceProvider _serviceProvider;
    
        public HangfireActivator(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
    
        public override object ActivateJob(Type type)
        {
            return _serviceProvider.GetService(type);
        }
    }  
  3. Ensuite, enregistrez hangfire en tant que service dans la section Startup.ConfigureServices méthode :

    services.AddHangfire(opt => 
        opt.UseSqlServerStorage("Your Hangfire Connection string"));
  4. Configurer hangfire dans le Startup.Configure méthode. Pour répondre à votre question, le clé est de configurer hangfire pour utiliser la nouvelle HangfireActivator que nous venons de définir ci-dessus. Pour ce faire, vous devrez fournir à hangfire l'information suivante IServiceProvider et cela peut être réalisé en l'ajoutant simplement à la liste des paramètres de l'option Configure méthode. Au moment de l'exécution, DI fournira ce service pour vous :

    public void Configure(
        IApplicationBuilder app, 
        IHostingEnvironment env, 
        ILoggerFactory loggerFactory,
        IServiceProvider serviceProvider)
    {
        ...
    
        // Configure hangfire to use the new JobActivator we defined.
        GlobalConfiguration.Configuration
            .UseActivator(new HangfireActivator(serviceProvider));
    
        // The rest of the hangfire config as usual.
        app.UseHangfireServer();
        app.UseHangfireDashboard();
    }  
  5. Lorsque vous mettez un travail en file d'attente, utilisez le type enregistré qui est généralement votre interface. N'utilisez pas un type concret, sauf si vous l'avez enregistré de cette façon. Vous devez utiliser le type enregistré avec votre IoC, sinon Hangfire ne le trouvera pas. Par exemple dites que vous avez enregistré les services suivants :

    services.AddScoped<DbManager>();
    services.AddScoped<IMyService, MyService>();

Vous pourriez alors mettre en file d'attente DbManager avec une version instanciée de la classe :

    BackgroundJob.Enqueue(() => dbManager.DoSomething());

Cependant, vous ne pouvez pas faire la même chose avec MyService . La mise en file d'attente d'une version instanciée échouerait parce que le DI échouerait car seule l'interface est enregistrée. Dans ce cas, la mise en file d'attente se fait de la manière suivante :

    BackgroundJob.Enqueue<IMyService>( ms => ms.DoSomething());

1 votes

Il convient de noter que dans le ms => ms.DoSomething() Dans ce cas, l'expression debe appeler une méthode sur le paramètre passé. Vous ne pouvez pas faire ms => Foo.StaticMethod(ms) ; Hangfire donne une exception cryptique dans ce cas.

33 votes

La version actuelle de Hangfire (1.6.19) enregistre automatiquement AspNetCoreJobActivator. github.com/HangfireIO/Hangfire/blob/master/src/

0 votes

De plus, les méthodes d'extension ne fonctionnent pas avec Hangfire. Il faut créer un wrapper.

29voto

Daniel Genezini Points 59

La réponse de DoritoBandito est incomplète ou dépréciée.

public class EmailSender {
     public EmailSender(IDbContext dbContext, IEmailService emailService)
     {
         _dbContext = dbContext;
         _emailService = emailService;
     }
}

Services de registre :

services.AddTransient<IDbContext, TestDbContext>();
services.AddTransient<IEmailService, EmailService>();

Enqueue :

BackgroundJob.Enqueue<EmailSender>(x => x.Send(13, "Hello!"));

Source : http://docs.hangfire.io/en/latest/background-methods/passing-dependencies.html

2 votes

C'est la manière correcte d'atteindre les exigences de l'OP.

0 votes

La clé ici est que lorsque vous utilisez le <Type> entre parenthèses, un nouvel objet est créé ; et ensuite une action est exécutée sur lui . Assurez-vous d'ajouter le SERVICE pour que cela fonctionne.

14voto

DoritoBandito Points 124

Pour autant que je sache, vous pouvez utiliser l'injection de dépendance des noyaux .net comme vous le feriez pour n'importe quel autre service.

Vous pouvez utiliser un service qui contient les tâches à exécuter, qui peut être exécuté comme suit

var jobId = BackgroundJob.Enqueue(x => x.SomeTask(passParamIfYouWish));

Voici un exemple de la classe Job Service

public class JobService : IJobService
{
    private IClientService _clientService;
    private INodeServices _nodeServices;

    //Constructor
    public JobService(IClientService clientService, INodeServices nodeServices)
    {
        _clientService = clientService;
        _nodeServices = nodeServices;
    }

    //Some task to execute
    public async Task SomeTask(Guid subject)
    {
        // Do some job here
        Client client = _clientService.FindUserBySubject(subject);
    }      
}

Et dans votre projet Startup.cs vous pouvez ajouter une dépendance comme d'habitude

services.AddTransient< IClientService, ClientService>();

Je ne suis pas sûr que cela réponde à votre question

5 votes

Cette solution fonctionne dès le départ. Merci

1 votes

J'ai également eu des dépendances qui ont été résolues dès le départ sans mettre en œuvre JobActivator

4 votes

Comment cela fonctionne-t-il en dehors de la boîte ? Donc ClientService est juste votre propre API. Comment BackgroundJob sait-il qu'il doit appeler une instance de JobService ? IJobService est-il une interface hangfire ? Si oui, je ne la trouve pas. Je suis très confus !

3voto

Ehsan Mirsaeedi Points 128

Actuellement, Hangfire est profondément intégré à Asp.Net Core. Installer Hangfire.AspNetCore a configuration du tableau de bord et l'intégration DI automatiquement. Ensuite, il vous suffit de définir vos dépendances en utilisant ASP.NET core comme toujours.

0voto

J'ai dû lancer HangFire dans la fonction principale. Voici comment j'ai résolu le problème :

public static void Main(string[] args)
    {
        var host = CreateWebHostBuilder(args).Build();
        using (var serviceScope = host.Services.CreateScope())
        {
            var services = serviceScope.ServiceProvider;

            try
            {
                var liveDataHelper = services.GetRequiredService<ILiveDataHelper>();
                var justInitHangfire = services.GetRequiredService<IBackgroundJobClient>();
                //This was causing an exception (HangFire is not initialized)
                RecurringJob.AddOrUpdate(() => liveDataHelper.RePopulateAllConfigDataAsync(), Cron.Daily());
                // Use the context here
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "Can't start " + nameof(LiveDataHelper));
            }
        }
        host.Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X