Após vermos como utilizar o Hangfire em um post anterior, e conforme prometido, vamos ver como utilizar um container IoC (inversão de controle) em conjunto com o Hangfire. Para começarmos, vamos ver como o Hangfire faz para criar um job com um objeto que nós desejamos. Por exemplo, imagine que temos a seguinte classe:
using System; using System.Diagnostics; namespace WebDemoHangfire { public class DemoJob { public void Execute() { Debug.WriteLine($"Fire and forget: {DateTime.Now}"); } } }
Quando criamos um job, podemos criar da seguinte forma:
BackgroundJob.Enqueue(() => new DemoJob().Execute());
O que acontece nesse caso, é que nós somos responsáveis por criar uma instância de DemoJob, e passar a instância como parâmetro para o Hangfire, e esse cenário faz sentido em alguns casos, mas, em outros casos, e acredito que sejam a maioria, nós não precisaríamos nos preocupar em passar um objeto criado para o Hangfire, e sim apenas qual o método que queremos executar, para esses casos, nós podemos criar nosso job da seguinte forma:
BackgroundJob.Enqueue<DemoJob>(j => j.Execute());
Mais simples e prático certo? Mas, ainda temos um problema, pois dessa forma passamos ao Hangfire a responsabilidade em criar nossa classe, o que é bom, porém, por padrão, o Hangfire utiliza o Activator.CreateInstance para criar nossa classe, e só consegue criar classes que tenham um construtor sem parâmetros, o que resolve boa parte dos casos, mas, se nossa classe tivesse o código abaixo, nós teríamos um problema:
using System; namespace WebDemoHangfire { public class DemoJob { private ILogger logger; public DemoJob(ILogger logger) { this.logger = logger; } public void Execute() { logger.WriteLine($"Fire and forget: {DateTime.Now}"); } } }
O problema aqui é que precisamos receber um ILogger como parâmetro para que nosso Job funcione, e o Hangfire não sabe criar um objeto do tipo ILogger. Para resolver isso, usamos um container IoC, que já vimos alguns deles aqui anteriormente, assim como vimos como utilizá-los em uma aplicação console .net core e uma aplicação web asp.net core. Agora vamos à mão na massa, e para o exemplo de hoje, vamos nos basear na aplicação que fizemos em nosso post anterior sobre o Hangfire que está disponível no GitHub clicando aqui.
Após abrir a aplicação no Visual Studio 2017, vamos criar nossa interface ILogger com o conteúdo abaixo:
namespace WebDemoHangfire { public interface ILogger { void WriteLine(string message); } }
Agora vamos criar uma classe que implemente nossa interface, e vamos chamá-la de DebugLogger:
using System.Diagnostics; namespace WebDemoHangfire { public class DebugLogger : ILogger { public void WriteLine(string message) => Debug.WriteLine(message); } }
E por fim, vamos criar a classe DemoJob que irá representar o nosso Job:
using System; namespace WebDemoHangfire { public class DemoJob { private ILogger logger; public DemoJob(ILogger logger) { this.logger = logger; } public void Execute() => logger.WriteLine($"DemoJob: {DateTime.Now}"); } }
Em nossa classe DemoJob estamos recebendo um objeto do tipo ILogger em nosso construtor, e quem será responsável por criá-lo e passar para nossa classe vai ser o container IoC. Agora vamos alterar a classe JobsController para que o método Get agende um job de nossa nova classe, para isso adicione a linha:
BackgroundJob.Enqueue<DemoJob>(j => j.Execute());
Agora, nós precisamos dizer ao Hangfire para usar o container e não mais o Activator, e para isso nós precisamos criar uma classe que herde de JobActivator, e sobrescrever o método ActivateJob. Vamos então criar uma classe com o nome ContainerJobActivator, com o código abaixo:
using Hangfire; using System; namespace WebDemoHangfire { public class ContainerJobActivator : JobActivator { private IServiceProvider _serviceProvider; public ContainerJobActivator(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public override object ActivateJob(Type type) => _serviceProvider.GetService(type); } }
O que fizemos aqui, foi criar uma classe que recebe um IServiceProvider como parâmetro no construtor, que é o container responsável pela criação dos objetos que precisamos. E no método ActivateJob, nós pedimos ao container que crie para nós um objeto do tipo solicitado.
E por fim, nós precisamos alterar o método Configure da classe Startup, e a primeira modificação que devemos fazer nele é acrescentar em sua lista de parâmetros o IServiceProvider, deixando a sua assinatura dessa forma:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider serviceProvider)
Agora, antes da linha que faz a chamada à UseHangfireServer, nós devemos adicionar a seguinte linha:
GlobalConfiguration.Configuration.UseActivator(new ContainerJobActivator(serviceProvider));
O método completo fica dessa forma:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider serviceProvider) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); GlobalConfiguration.Configuration.UseActivator(new ContainerJobActivator(serviceProvider)); app.UseHangfireServer(); app.UseHangfireDashboard(); app.UseMvc(); }
Pronto, o Hangfire já sabe utilizar o container para criar nossas classes, mas, ainda falta nós informarmos ao container como ele cria as nossas classes, então vamos registrá-las, e para isso, vamos alterar o método ConfigureServices também da classe Startup, adicionando as seguintes linhas:
services.AddTransient<DemoJob>(); services.AddTransient<ILogger, DebugLogger>();
O método completo ficará da seguinte forma:
public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddTransient<DemoJob>(); services.AddTransient<ILogger, DebugLogger>(); services.AddHangfire(x => x.UseSqlServerStorage("Data Source=localhost;Initial Catalog=hangfire;User id=hangfire;Password=hangfire;")); services.AddMvc(); }
Agora vamos rodar nossa aplicação e ver o resultado da execução impresso no console.
Nós podemos utilizar outro container IoC, como o Autofac por exemplo, e nós iremos ver como fazer isso em um próximo post, fique ligado em nosso espaço.
O código completo do nosso exemplo está no GitHub: https://github.com/desenvolvedorninja/hangfire-com-container-ioc.

Quase 20 anos de experiência no mercado de TI.
Atuação em grandes empresas como Netshoes, Borland, JBS, Bradesco, Hospital das Clínicas, Rede, Prodam, HSPE, Instituto Ayrton Senna, e também em empresas internacionais como Delta Dental, T-Mobile, Pepsi e Mckesson.
Fundador da TecPrime Solutions, administrador da comunidade nopCommerce Brasil, e autor dos sites InvestFacil.net e Desenvolvedores.ninja
1 thought on “Hangfire – utilizando com um container IoC”