Quartz.NET trigger does not fire, MVC4

后端 未结 2 2135
无人共我
无人共我 2020-12-30 16:54

I have a MVC4 .Net web application on 3-tier architecture with Unity dependency injection, and I want to shedule everyday a verficiation and send some mails where is the cas

相关标签:
2条回答
  • 2020-12-30 17:41

    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();
    
    0 讨论(0)
  • 2020-12-30 17:45

    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).

    0 讨论(0)
提交回复
热议问题