Hangfire循环作业调用方法是Startup使用现有服务



我试图设置Hangfire以独立方法在Startup.cs内运行循环作业。为了使其工作,我需要抓取一些我已经注入的ApplicationServices。但是作业执行失败,出现以下错误:

Recurring job 'Job: Dispatch Email from Queue' can't be scheduled due to an error and will be retried in 00:00:15.
System.InvalidOperationException: Recurring job can't be scheduled, see inner exception for details.
---> Hangfire.Common.JobLoadException: Could not load the job. See inner exception for the details.
---> Newtonsoft.Json.JsonSerializationException: Could not create an instance of type DA.BrrMs.Application.Interfaces.ServiceInterfaces.IBudgetReleaseRequestService. Type is an interface or abstract class and cannot be instantiated.

我有:

public class Startup
{
private IConfiguration Configuration { get; }
private RecurringJobManager _jobManager;
public Startup(IConfiguration configuration) => Configuration = configuration;
public void ConfigureServices(IServiceCollection services)
{
...
if (Configuration["SystemSettings:UseHangfire"] == "1")
{
services.AddHangfire(c => c.UseMemoryStorage());
JobStorage.Current = new MemoryStorage();
services.AddHangfireServer();
GlobalConfiguration.Configuration.UseMemoryStorage();
}
RegisterServices(services);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
var requestService = app.ApplicationServices.GetService<IBudgetReleaseRequestService>();
var mailService    = app.ApplicationServices.GetService<IMailer>();
_jobManager = new RecurringJobManager();
_jobManager.AddOrUpdate("Job: Dispatch Email from Queue", () => StartupMailJob(requestService, mailService), Cron.Minutely);
}
private static void RegisterServices(IServiceCollection services) => DependencyContainer.RegisterServices(services);
public static async Task StartupMailJob(IBudgetReleaseRequestService requestService, IMailer mailService)
{
try
{
var emailsToSend = await requestService.DispatchEmails();
// Send emails
foreach (var emailToSend in emailsToSend)
{
}
// Update status of sent                
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
// In a project, far far away...
public static void RegisterServices(IServiceCollection services)
{
...
services.AddScoped<IBudgetReleaseRequestService, BudgetReleaseRequestService>();
...
}

如何满足Hangfire对类实例而不是接口的要求?

这是我发现最适合我的实现:

1在Startup.cs

中注册我想要调度的服务
services.AddScoped<IMyJob, MYJob>();

2创建了一个激活器类,用于定义作业执行的范围。

public class HangFireActivatorMyJob : IHangFireActivatorMyJob
{
private readonly IServiceProvider _serviceProvider;
public HangFireActivatorMyJob (IServiceProvider serviceProvider)
{
this._serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
}
public async Task Run(IJobCancellationToken token)
{
token.ThrowIfCancellationRequested();
await RunAtTimeOf(DateTime.Now);
}
public async Task RunAtTimeOf(DateTime now)
{
using IServiceScope scope = this._serviceProvider.CreateScope();
var myJobService= scope.ServiceProvider.GetRequiredService<IMyJob>();
await myJobService.RunSomeTaskOnJob();
}
}

3注册激活器

services.AddTransient<IHangFireActivatorMyJob, HangFireActivatorMyJob >();

4将IRecurringJobManager接口添加到Startup.cs

中的configure方法中
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
IRecurringJobManager recurringJobManager)

5将作业添加到提供的IRecurringJobManager

recurringJobManager.AddOrUpdate<HangFireActivatorMyJob >(nameof(HangFireActivatorMyJob ),
job => serviceProvider.GetRequiredService<IHangFireActivatorMyJob>()
.Run(JobCancellationToken.Null)
, Cron.Hourly(3), TimeZoneInfo.Utc);

最新更新