4

I am trying to schedule a task using Quartz.net 2.0 in ASP.NET MVC 4 application, but i can not get the task to be executed.

Here is the code:

public class ScheduleTaskConfig
{
    public static void StartScheduler()
    {
        ISchedulerFactory schedulerFactory = new StdSchedulerFactory();

        IScheduler scheduler = schedulerFactory.GetScheduler();

        JobKey emailSenderTaskKey = new JobKey("emailSenderTask", "email");
        IJobDetail emailSenderTask = JobBuilder.Create<QueuedEmailsSendTask>()
            .WithIdentity(emailSenderTaskKey)
            .Build();

        TriggerKey emailSenderTriggerKey = new TriggerKey("emailSenderTrigger", "email");
        ITrigger emailSenderTrigger = TriggerBuilder.Create()
            .WithIdentity(emailSenderTriggerKey)
            .WithSimpleSchedule(s => s.RepeatForever().WithIntervalInSeconds(5))
            .StartNow()
            .Build();

        scheduler.ScheduleJob(emailSenderTask, emailSenderTrigger);
        scheduler.Start();
    }
}

It is called in global.asax application start

protected void Application_Start()
{
    ScheduleTaskConfig.StartScheduler();
    ...
}

And here is the class that implements the IJob interface:

public class QueuedEmailsSendTask : IJob
{
    private IQueuedEmailsService _queuedEmailsService { get; set; }
    private IEmailSenderService _emailSenderService { get; set; }

    public QueuedEmailsSendTask(IQueuedEmailsService queuedEmailsService, IEmailSenderService emailSenderService)
    {
        this._queuedEmailsService = queuedEmailsService;
        this._emailSenderService = emailSenderService;
    }

    public void Execute(IJobExecutionContext executeContext)
    {
        //do stuff ...
    }
}

I placed a breakpoint at the beginning of the Execute method, but the debugger does not stop there. What am i doing wrong?

UPDATE: It has something to do with the class that implements the IJob interface not having a default constructor. It works, if I modify the constructor like this:

public QueuedEmailsSendTask()
{
}

But I need to be able to inject my dependencies. I am using the Autofac IoC container.

Marius Stănescu
  • 3,603
  • 2
  • 35
  • 49
  • Implementing Recurring Background Tasks In ASP.NET is not a very good idea (more info [here](http://haacked.com/archive/2011/10/16/the-dangers-of-implementing-recurring-background-tasks-in-asp-net.aspx)). – david.s May 21 '13 at 08:33

3 Answers3

7

To make Quartz.net work with an IoC container you need to have a factory class implementing IJobFactory:

public class AutofacJobFactory : IJobFactory
{
    private readonly IContainer _container;

    public AutofacJobFactory(IContainer container)
    {
        _container = container;
    }

    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    {
        return (IJob)_container.Resolve(bundle.JobDetail.JobType);
    }
}

The JobFactory instance then needs to be assigned to the scheduler in the initialization code:

ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
IScheduler scheduler = schedulerFactory.GetScheduler();
scheduler.JobFactory = new AutofacJobFactory(container);

And don't forget to register the job in the IoC container.

david.s
  • 11,283
  • 6
  • 50
  • 82
  • When i debug, in the NewJob method I get the following exception: "No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself." – Marius Stănescu May 21 '13 at 08:14
1

Have you tried scheduling the job after starting the scheduler?

public class ScheduleTaskConfig
{
    public static void StartScheduler()
    {
        ISchedulerFactory schedulerFactory = new StdSchedulerFactory();

        IScheduler scheduler = schedulerFactory.GetScheduler();
        scheduler.Start(); //start here   

        //construct job info

        scheduler.ScheduleJob(emailSenderTask, emailSenderTrigger); //schedule here
    }
}
Nick Patsaris
  • 2,118
  • 1
  • 16
  • 18
0

You need to ensure that the AutofacJobFactory is responsible for instantiating the job. This means not using the JobBuilder object. Instead you should pass the details of the job to be created by the scheduler's AutofacJobFactory in the form of a JobDetailImpl object. Your working code would look something like the following.

ISchedulerFactory schedulerFactory = new StdSchedulerFactory();

IScheduler scheduler = schedulerFactory.GetScheduler();
scheduler.JobFactory = new AutofacJobFactory(container);
scheduler.Start(); //start here  

// construct job info
JobDetailImpl jobDetail = new JobDetailImpl("emailSenderTask", null, typeof(QueuedEmailsSendTask));

TriggerKey emailSenderTriggerKey = new TriggerKey("emailSenderTrigger", "email");
ITrigger emailSenderTrigger = TriggerBuilder.Create()
    .WithIdentity(emailSenderTriggerKey)
    .WithSimpleSchedule(s => s.RepeatForever().WithIntervalInSeconds(5))
    .StartNow()
    .Build();

sched.ScheduleJob(jobDetail, trigger);

For a complete example, please see the following question How do I create a Quartz.NET’s job requiring injection with autofac

Community
  • 1
  • 1
dcarson
  • 2,853
  • 1
  • 25
  • 34