使用 Quartz.NET 和 Simple Injector 进行构造函数注入

Posted

技术标签:

【中文标题】使用 Quartz.NET 和 Simple Injector 进行构造函数注入【英文标题】:Constructor injection with Quartz.NET and Simple Injector 【发布时间】:2013-01-11 19:11:45 【问题描述】:

目前我正在使用 Quartz.NET 编写一个服务来安排它的运行。

我想知道是否有人有使用 Quartz.NET 和 Simple Injector 的构造函数注入的经验。

以下基本上是我希望实现的目标

public class JobImplementation: IJob

    private readonly IInjectedClass injectedClass;

    public JobImplementation(IInjectedClass _injectedClass)
    
         injectedClass = _injectedClass
    

    public void Execute(IJobExecutionContext _context)
    
        //Job code
    

【问题讨论】:

【参考方案1】:

根据this blog post,您需要实现一个自定义IJobFactory,如下所示:

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

此外,您还需要以下注册:

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();

【讨论】:

谢谢。一个小问题,StdSchedulerFactory 类有 2 个构造函数,有没有告诉 simpleinjector 使用零参数构造函数? 我不得不搜索它并认为注意以下石英配置是您告诉它使用注入友好作业工厂实现的方式会有所帮助: 我必须以与上面稍有不同的方式注册调度程序才能放入 jobFactory。使用 XML 不起作用,因为它强制要求默认构造函数。因此,除了 Steven 的帖子之外,我还添加了 container.RegisterSingle(() => var scheduler = schedulerFactory.GetScheduler(); scheduler.JobFactory = container.GetInstance(); return scheduler; );跨度> 太棒了!另请注意,使用 Quartz.Net 2.0,需要实现 public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) ...。并且不确定是否应该在public void ReturnJob(IJob job)... 中实现任何清理调用。 这似乎不适用于最新版本的 Quartz 和 SimpleInjector。我没有 ILoadServiceScheduler、TimerScheduler、LoggingJobDecorator。另外,我如何获得 applicationAssemblies?我在这里很困惑,无法弄清楚这一点。 :)【参考方案2】:

迟到了,但https://github.com/hbiarge/Quartz.Unity 非常适合结合 Quartz.NET 和 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();

【讨论】:

【参考方案3】:

通过 asp.net 核心的依赖注入引擎使用 Quartz.net 只需几个步骤。

将 nuget 包添加到您的项目中:

Microsoft.Extensions.DependencyInjection

创建自定义 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();
 

配置调度器时指定JobFactory:

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

对于某人来说,在板上使用 Quartz.net 和 DI(来自 asp.net 核心)作为 win 服务的有用示例:

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();

【讨论】:

以上是关于使用 Quartz.NET 和 Simple Injector 进行构造函数注入的主要内容,如果未能解决你的问题,请参考以下文章

Quartz.net 3.x使用总结——Db持久化和集群

Quartz.NET总结Quartz 远程调度

.Net Core中使用Quartz.Net

Quartz.NET 配置文件详解

Quartz.NET 与 Windows 计划任务。他们有啥不同?

Quartz.net 3.x使用总结——简单使用