1

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.

David.Warwick
  • 620
  • 1
  • 9
  • 28
  • 1
    I haven't looked into much, but I found [this](https://stackoverflow.com/questions/14562176/constructor-injection-with-quartz-net-and-simple-injector) that might help – Timothy G. Dec 21 '21 at 04:24
  • Thank you. I just edited my question to show what helped me. I got everything working now. – David.Warwick Dec 21 '21 at 04:31

0 Answers0