Constructor injection with Quartz.NET and Simple Injector

前端 未结 3 1436
囚心锁ツ
囚心锁ツ 2020-12-02 13:04

Currently I am writing a service using Quartz.NET to schedule the running of it.

I was wondering if anyone has any experience of using constructor injection with Qua

相关标签:
3条回答
  • 2020-12-02 13:44

    Late to the party, but https://github.com/hbiarge/Quartz.Unity works well for combining Quartz.NET and Unity.

    IUnityContainer container = new UnityContainer();
    container.AddNewExtension<Quartz.Unity.QuartzUnityExtension>();
    // do your other Unity registrations
    IScheduler scheduler = container.Resolve<IScheduler>();
    
    scheduler.ScheduleJob(
        new JobDetailImpl(myCommandName, typeof(MyCommand)),
        TriggerBuilder.Create()
            .WithCronSchedule(myCronSchedule)
            .StartAt(startTime)
            .Build()
    );
    scheduler.Start();
    
    0 讨论(0)
  • 2020-12-02 13:45

    According to this blog post, you would need to implement a custom IJobFactory, like this:

    public class SimpleInjectorJobFactory : IJobFactory
    {
        private readonly Container container;
        private readonly Dictionary<Type, InstanceProducer> jobProducers;
    
        public SimpleInjectorJobFactory(
            Container container, params Assembly[] assemblies)
        {
            this.container = container;
    
            // By creating producers, jobs can be decorated.
            var transient = Lifestyle.Transient;
            this.jobProducers =
                container.GetTypesToRegister(typeof(IJob), assemblies).ToDictionary(
                    type => type,
                    type => transient.CreateProducer(typeof(IJob), type, container));
        }
    
        public IJob NewJob(TriggerFiredBundle bundle, IScheduler _)
        {
            var jobProducer = this.jobProducers[bundle.JobDetail.JobType];
            return new AsyncScopedJobDecorator(
                this.container, () => (IJob)jobProducer.GetInstance());
        }
    
        public void ReturnJob(IJob job)
        {
            // This will be handled automatically by Simple Injector
        }
    
        private sealed class AsyncScopedJobDecorator : IJob
        {
            private readonly Container container;
            private readonly Func<IJob> decorateeFactory;
    
            public AsyncScopedJobDecorator(
                Container container, Func<IJob> decorateeFactory)
            {
                this.container = container;
                this.decorateeFactory = decorateeFactory;
            }
    
            public async Task Execute(IJobExecutionContext context)
            {
                using (AsyncScopedLifestyle.BeginScope(this.container))
                {
                    var job = this.decorateeFactory();
                    await job.Execute(context);
                }
            }
        }
    }
    

    Furthermore, you'll need the following registrations:

    var container = new Container();
    
    container.Options.ScopedLifestyle = new AsyncScopedLifestyle();
    
    var factory = new StdSchedulerFactory();
    
    IScheduler scheduler = await factory.GetScheduler();
    
    scheduler.JobFactory = new SimpleInjectorJobFactory(
        container, 
        Assembly.GetExecutingAssembly()); // assemblies that contain jobs
    
    // Optional: register some decorators
    container.RegisterDecorator(typeof(IJob), typeof(LoggingJobDecorator));
    
    container.Verify();
    
    0 讨论(0)
  • 2020-12-02 13:56

    There are few steps to use Quartz.net with dependency injection engine from asp.net core.

    Add nuget package to your project:

    Microsoft.Extensions.DependencyInjection
    

    Create custom JobFactory:

    public class JobFactory : IJobFactory
    {
        protected readonly IServiceProvider _serviceProvider;
    
         public JobFactory(IServiceProvider serviceProvider) 
             => _serviceProvider = serviceProvider;
    
         public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
             => _serviceProvider.GetService(bundle.JobDetail.JobType) as IJob;
    
         public void ReturnJob(IJob job) 
             => (job as IDisposable)?.Dispose();
     }
    

    Specify JobFactory when configuring scheduler:

     var scheduler = await StdSchedulerFactory.GetDefaultScheduler();
     scheduler.JobFactory = new JobFactory(_serviceProvider);
    

    For someone can be usefull example of win service with Quartz.net and DI (from asp.net core) on the board:

    public class WinService : ServiceBase
    {
        private Scheduler _scheduleManager;
    
        private readonly Startup _startup;
    
        public WinService()
        {
            ServiceName = "SomeWinService";
            _startup = new Startup();
        }
    
        static void Main(string[] args)
        {
            var service = new WinService();
    
            // Working as Windows-service
            if (Console.IsInputRedirected && Console.IsOutputRedirected)
            {
                ServiceBase.Run(service);
            }
            // Working as console app
            else
            {
                service.OnStart(args);
                Console.WriteLine("Press any key to stop...");
                Console.ReadKey();
                service.OnStop();
            }
        }
     
        protected override void OnStart(string[] args)
        {
            _startup.RegisterServices();
            _scheduleManager = new Scheduler(_startup.ServiceProvider);
            _scheduleManager.StartTracking().Wait();
        }
    
        protected override void OnPause()
            => _scheduleManager.PauseTracking().Wait();
    
        protected override void OnContinue()
            => _scheduleManager.ResumeTracking().Wait();
     
        protected override void OnStop()
        {
            _scheduleManager.StopTracking().Wait();
            _startup.DisposeServices();
        }
    }
    
    public class Startup
    {
        private IServiceProvider _serviceProvider;
    
        public IServiceProvider ServiceProvider => _serviceProvider;
    
        public void RegisterServices()
        {        
            _serviceProvider = new ServiceCollection()
                //.AddTransient(...)
                //.AddScoped(...)
                //.AddSingleton(...)
                .BuildServiceProvider();
    
        }
    
        public void DisposeServices()
        {
            if (_serviceProvider == null)
                return;
    
            if (_serviceProvider is IDisposable)
            {
                ((IDisposable)_serviceProvider).Dispose();
            }
        }
    }
    
    public class Scheduler
    {        
        private readonly IServiceProvider _serviceProvider;
       
        private IScheduler _scheduler;
       
        public Scheduler(IServiceProvider serviceProvider) 
            => _serviceProvider = serviceProvider;
       
        public async Task StartTracking()
        {
            _scheduler = await StdSchedulerFactory.GetDefaultScheduler();
            _scheduler.JobFactory = new JobFactory(_serviceProvider);
            await _scheduler.Start();
           
            // Schedule your jobs here
        }
      
        public async Task PauseTracking() => await _scheduler?.PauseAll();
       
        public async Task ResumeTracking() => await _scheduler?.ResumeAll();
      
        public async Task StopTracking() => await _scheduler?.Shutdown();
    }
    
    0 讨论(0)
提交回复
热议问题