Quartz.NET trigger does not fire, MVC4

不羁岁月 提交于 2019-11-30 07:36:11
LeftyX

Quartz.net Scheduler must be created as singleton.

You can install Unity.MVC4 NuGet Package.
It will create a Bootstrapper class which should look something like this:

public static class Bootstrapper
{
    public static IUnityContainer Initialise()
    {
        var container = BuildUnityContainer();
        DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        return container;
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();
        // Register your interfaces here. 
        RegisterTypes(container);
        return container;
    }

    public static void RegisterTypes(IUnityContainer container)
    {
    }
}

Then you have to create your own implementation of JobFactory. This article might help you and this one is worth reading:

public class UnityJobFactory: IJobFactory
{
    private readonly IUnityContainer container;

    static UnityJobFactory()
    {
    }

    public UnityJobFactory(IUnityContainer container)
    {
        this.container = container;
    }

    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    {
        var jobDetail = bundle.JobDetail;
        var jobType = jobDetail.JobType;

        try
        {
            return this.container.Resolve(jobType) as IJob;
        }
        catch (Exception ex)
        {
            throw new SchedulerException(string.Format(
                CultureInfo.InvariantCulture,
                "Cannot instantiate class '{0}'", new object[] { jobDetail.JobType.FullName }), ex);
        }
    }

    public void ReturnJob(IJob job)
    {
        // Nothing here. Unity does not maintain a handle to container created instances.
    }
}

and your own implementation of StdSchedulerFactory:

public class UnitySchedulerFactory : StdSchedulerFactory
{
    private readonly UnityJobFactory unityJobFactory;

    public UnitySchedulerFactory(UnityJobFactory unityJobFactory)
    {
        this.unityJobFactory = unityJobFactory;
    }

    protected override IScheduler Instantiate(QuartzSchedulerResources rsrcs, QuartzScheduler qs)
    {
        qs.JobFactory = this.unityJobFactory;
        return base.Instantiate(rsrcs, qs);
    }
}

Going back to your Unity Bootstrapper you have to register your interfaces:

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();

        container.RegisterType<ISchedulerFactory, UnitySchedulerFactory>(new ContainerControlledLifetimeManager());
        container.RegisterType<IScheduler>(new InjectionFactory(c => c.Resolve<ISchedulerFactory>().GetScheduler()));
        container.RegisterType<IQuartzScheduler, QuartzScheduler>(new ContainerControlledLifetimeManager());
        container.RegisterType<IEvaluationBus, EvaluationBus>();

        RegisterTypes(container);

        return container;
    }

I've wrapped up my service scheduler in a class so that I can create it singleton:

public interface IQuartzScheduler
{
    void Run();
    void Stop();
}

and:

public class QuartzScheduler : IQuartzScheduler
{
    private readonly ISchedulerFactory SchedulerFactory;
    private readonly IScheduler Scheduler;

    public QuartzScheduler(ISchedulerFactory schedulerFactory, IScheduler scheduler)
    {
        this.SchedulerFactory = schedulerFactory;
        this.Scheduler = scheduler;
    }

    public void Run()
    {
        IJobDetail dailyUserMailJob = new JobDetailImpl("DailyUserMailJob", null, typeof(Scheduler.SchedulerJob));
        // fire every time I open App/EveryDay
        ITrigger dailyUserMailTrigger = new SimpleTriggerImpl("DailyUserMailTrigger", 10,
                                                 new TimeSpan(0, 0, 0, 20));

        this.Scheduler.ScheduleJob(dailyUserMailJob, dailyUserMailTrigger);

        this.Scheduler.Start();
    }

    public void Stop()
    {
        this.Scheduler.Shutdown(false);
    }
}

As you can see in this class I'll create my jobs/trigger and start the scheduler.

now in your Application_Start (global.asax) you can "bootstrap" your Unity Container, get the service scheduler and run it.

var unityContainer = Infrastructure.Bootstrapper.Initialise();
unityContainer.Resolve<IQuartzScheduler>().Run();

You can find a working sample following this link (QuartzWithUnity).

Very useful, thanks LeftyX. I think, in Application_Start you have to create servise like this:

var unityContainer = Bootstrapper.Initialise();
QuartzScheduler jobService = (QuartzScheduler)unityContainer.Resolve(typeof(QuartzScheduler), "Jobs");
jobService.Run();
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!