Взаимодействие зависимостей Hangfire с ядром .net

Как я могу использовать инъекцию зависимостей ядра ядра .net в Hangfire?

Я новичок в Hangfire и ищу пример, который работает с ядром asp.net.

Ответы

Ответ 1

Смотрите полный пример на GitHub https://github.com/gonzigonz/HangfireCore-Example.
Живой сайт по адресу http://hangfirecore.azurewebsites.net/

  1. Убедитесь, что у вас есть базовая версия Hangfire:
    dotnet add package Hangfire.AspNetCore

  2. Настройте свой IoC, определив JobActivator. Ниже приведена конфигурация для использования со стандартной службой ядра контейнера asp.net:

    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. Затем зарегистрируйте hangfire как службу в методе Startup.ConfigureServices:

    services.AddHangfire(opt => 
        opt.UseSqlServerStorage("Your Hangfire Connection string"));
    
  4. Настройка замедленного воспламенения в Startup.Configure методе. В связи с вашим вопросом, ключ заключается в том, чтобы настроить Hangfire для использования нового HangfireActivator мы только что определили выше. Для этого вам нужно будет предоставить hangfire с IServiceProvider и этого можно достичь, просто добавив его в список параметров для метода Configure. Во время выполнения DI предоставит вам эту услугу:

    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. Когда вы ставите задачу в очередь, используйте зарегистрированный тип, который обычно является вашим интерфейсом. Не используйте конкретный тип, если вы не зарегистрировали его таким образом. Вы должны использовать тип, зарегистрированный в вашем IoC, иначе Hangfire не найдет его. Например, скажем, вы зарегистрировали следующие услуги:

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

Затем вы можете поставить в очередь DbManager с DbManager инстанцированной версией класса:

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

Однако вы не можете сделать то же самое с MyService. Постановка в очередь с инстанцированной версией не удалась бы, потому что DI потерпел бы неудачу, поскольку зарегистрирован только интерфейс. В этом случае вы бы поставили в очередь вот так:

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

Ответ 2

Насколько мне известно, вы можете использовать инъекцию зависимостей ядра .net так же, как и для любой другой службы.

Вы можете использовать сервис, который содержит выполняемые задания, которые могут выполняться так

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

Ниже приведен пример класса 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);
    }      
}

И в ваших проектах Startup.cs вы можете добавить зависимость как обычно

services.AddTransient< IClientService, ClientService>();

Не уверен, что это отвечает на ваш вопрос или нет.

Ответ 3

DoritoBandito ответ неполный или не рекомендуется.

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

Регистрация услуг:

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

Ставить:

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

Источник: http://docs.hangfire.io/en/latest/background-methods/passing-dependencies.html

Ответ 5

Мне пришлось запустить HangFire в основной функции. Вот как я это решил:

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

Ответ 6

Если вы пытаетесь быстро настроить Hangfire с помощью ASP.NET Core (протестировано в ASP.NET Core 2.2), вы также можете использовать Hangfire.MemoryStorage. Все настройки можно выполнить в Startup.cs:

using Hangfire;
using Hangfire.MemoryStorage;

public void ConfigureServices(IServiceCollection services) 
{
    services.AddHangfire(opt => opt.UseMemoryStorage());
    JobStorage.Current = new MemoryStorage();
}

protected void StartHangFireJobs(IApplicationBuilder app, IServiceProvider serviceProvider)
{
    app.UseHangfireServer();
    app.UseHangfireDashboard();

    //TODO: move cron expressions to appsettings.json
    RecurringJob.AddOrUpdate<SomeJobService>(
        x => x.DoWork(),
        "* * * * *");

    RecurringJob.AddOrUpdate<OtherJobService>(
        x => x.DoWork(),
        "0 */2 * * *");
}

public void Configure(IApplicationBuilder app, IServiceProvider serviceProvider)
{
    StartHangFireJobs(app, serviceProvider)
}

Конечно, все хранится в памяти и теряется после перезапуска пула приложений, но это быстрый способ увидеть, что все работает, как ожидается, с минимальной конфигурацией.

Чтобы переключиться на постоянство базы данных SQL Server, вы должны установить пакет Hangfire.SqlServer и просто настроить его вместо хранения в памяти:

services.AddHangfire(opt => opt.UseSqlServerStorage(Configuration.GetConnectionString("Default")));