I am trying to utilize Quartz.Net Quartz Quick Start Guide to schedule a job for my ASP.Net web application. I am using ASP.Net Core 5.
I have installed the Nuget Packages Quartz.ASPNetCore
and Quartz.Extensions.DependencyInjection
. I have been able to execute the sample job of outputing to the console every 10 seconds. No problem.
But now in the actual job, I need to access AppDbContext so I can use entity framework to access my database. This is where I am having an issue. If I add AppDBContext to my IJob class, my job won't run because the job requires an empty public constructor.
So then I read that Quartz has been updated to allow dependency injection through IJobFactory, but I don't know if that is deprecated or not, but there doesn't seem to be any information on that on their website.
Here is my code:
services.AddSingleton<IJobFactory, SingletonJobFactory>();
services.AddSingleton<PayoutsJob>();
services.AddQuartz(q =>
{
// handy when part of cluster or you want to otherwise identify multiple schedulers
q.SchedulerId = "Scheduler-Core";
// we take this from appsettings.json, just show it's possible
// q.SchedulerName = "Quartz ASP.NET Core Sample Scheduler";
// as of 3.3.2 this also injects scoped services (like EF DbContext) without problems
q.UseMicrosoftDependencyInjectionJobFactory();
// or for scoped service support like EF Core DbContext
// q.UseMicrosoftDependencyInjectionScopedJobFactory();
// these are the defaults
q.UseSimpleTypeLoader();
q.UseInMemoryStore();
q.UseDefaultThreadPool(tp =>
{
tp.MaxConcurrency = 10;
});
});
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
ScheduleJobs();
}
private static async void ScheduleJobs()
{
// Grab the Scheduler instance from the Factory
StdSchedulerFactory factory = new StdSchedulerFactory();
IScheduler scheduler = await factory.GetScheduler();
// and start it off
await scheduler.Start();
// define the job and tie it to our HelloJob class
IJobDetail job = JobBuilder.Create<PayoutsJob>()
.WithIdentity("job1", "group1")
.Build();
// Trigger the job to run now, and then repeat every 10 seconds
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "group1")
//.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(10)
.RepeatForever())
.Build();
// Tell quartz to schedule the job using our trigger
await scheduler.ScheduleJob(job, trigger);
}
And my actual Job class:
public class PayoutsJob : IJob
{
public PayoutsJob()
{
}
public async Task Execute(IJobExecutionContext context)
{
//using (var scope = _services.CreateScope())
//{
// var dbContext = scope.ServiceProvider.GetService<AppDbContext>();
// List<ApplicationUser> sellers = await GetListOfSellers(dbContext);
//}
Log.Information("Payouts job starting.");
var result = await Paypal.CaptureOrderSample.CreatePayout();
Log.Information("Payouts job finished.");
Debug.WriteLine($"Status: {result.BatchHeader.BatchStatus}");
Debug.WriteLine($"Batch Id: {result.BatchHeader.PayoutBatchId}");
Debug.WriteLine("Links:");
foreach (PayoutsSdk.Payouts.LinkDescription link in result.Links)
{
Debug.WriteLine($"\t{link.Rel}: {link.Href}\tCall Type: {link.Method}");
}
}
private async Task<List<ApplicationUser>> GetListOfSellers(AppDbContext context) => await context.Users.Where(x => x.Subdomain != null).ToListAsync();
}
public class SingletonJobFactory : IJobFactory
{
private readonly IServiceProvider _serviceProvider;
public SingletonJobFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
return _serviceProvider.GetRequiredService(bundle.JobDetail.JobType) as IJob;
}
public void ReturnJob(IJob job) { }
}
What do I need to do to be able to access AppDBContext so that I can interact with EFCore from my IJob class?
Edit: I found the answer and I wanted to share. I followed this example I found here: Creating a Quartz.NET hosted service with ASP.NET Core
Rather than me posting all of the code, I pretty much cut and paste the code from the blog and it worked.