【问题标题】:Constructor injection with Quartz.NET and Simple Injector使用 Quartz.NET 和 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
    }

【问题讨论】:

    标签: c# .net dependency-injection quartz.net simple-injector


    【解决方案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();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多