2017-02-13 3 views
3

내 프로젝트에서 Quartz를 사용해야하지만 내가 뭘 잘못했는지 모른다.Quartz.Net Dependency Injection .Net Core

JobFactory :

public class IoCJobFactory : IJobFactory 
{ 
    private readonly IServiceProvider _factory; 

    public IoCJobFactory(IServiceProvider factory) 
    { 
     _factory = factory; 
    } 
    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) 
    { 
     return _factory.GetService(bundle.JobDetail.JobType) as IJob; 
    } 

    public void ReturnJob(IJob job) 
    { 
     var disposable = job as IDisposable; 
     if (disposable != null) 
     { 
      disposable.Dispose(); 
     } 
    } 
} 

QuartzExtensions :

public static class QuartzExtensions 
{ 
    public static void UseQuartz(this IApplicationBuilder app) 
    { 
     app.ApplicationServices.GetService<IScheduler>(); 
    } 

    public static async void AddQuartz(this IServiceCollection services) 
    { 
     var props = new NameValueCollection 
     { 
      {"quartz.serializer.type", "json"} 
     }; 
     var factory = new StdSchedulerFactory(props); 
     var scheduler = await factory.GetScheduler(); 

     var jobFactory = new IoCJobFactory(services.BuildServiceProvider()); 
     scheduler.JobFactory = jobFactory; 
     await scheduler.Start(); 
     services.AddSingleton(scheduler); 
    } 
} 

그리고 내 작업을 실행하려고하면 렸기 때문에 난 항상 예외가 (클래스 의존성 주입이) :

_factory.GetService(bundle.JobDetail.JobType) as IJob; 

입니다 항상 null입니다.

내 클래스는 IJob를 구현하고 startup.cs에 내가 추가 :

services.AddScoped<IJob, HelloJob>(); 
services.AddQuartz(); 

내가 표준 .NET 핵심 의존성 주입 사용

app.UseQuartz(); 

:

using Microsoft.Extensions.DependencyInjection; 
+0

DI에 직업을 설치하셨습니까? – Rabban

+0

예를 들어'services.AddScoped (); ' – donex93

답변

2

이를 내 응용 프로그램에서 어떻게했는지입니다. 스케줄러를 ioc에 추가하는 대신 공장 만 추가합니다.

services.AddTransient<IJobFactory, AspJobFactory>(
       (provider) => 
       { 
        return new AspJobFactory(provider); 
       }); 

제 직업 공장은 거의 같습니다. 어쨌든 한번만 이것을 사용하기 때문에 Transient는 중요하지 않습니다. 내 사용 석영 확장 방법 다음 Quartz 클래스뿐만 아니라 싱글이다

public static void UseQuartz(this IApplicationBuilder app, Action<Quartz> configuration) 
     { 
      // Job Factory through IOC container 
      var jobFactory = (IJobFactory)app.ApplicationServices.GetService(typeof(IJobFactory)); 
      // Set job factory 
      Quartz.Instance.UseJobFactory(jobFactory); 

      // Run configuration 
      configuration.Invoke(Quartz.Instance); 
      // Run Quartz 
      Quartz.Start(); 
     } 

입니다.

+0

'Quartz.Instance'가 excel의'scheduler'에 있습니까? 그리고'Action '그것은 무엇입니까? 내 Quartz는 Quartz가 네임 스페이스이기 때문에 유형처럼 사용된다 " – donex93

+0

'Quartz'는 제가 만든 맞춤 클래스입니다. 다음은 코드입니다. https://gist.github.com/Mats391/50cbf7f9c0291e623565dd0cc1baace3 – Mats391

+0

매우 도움이됩니다. 당신은 startup.cs에서'services.AddQuartz();'를 사용하지 않는다고 말할 수 있습니까? 그리고'UseQuartz'는 여러분의 Startup.cs에서 이것을 어떻게 추가 할 지에 대한 설정이 필요합니다. – donex93

1

이것은 해결하기 위해 IOC의 문제 내 솔루션의 단순한 예입니다 :

JobFactory.cs

public class JobFactory : IJobFactory 
    { 
     protected readonly IServiceProvider Container; 

     public JobFactory(IServiceProvider container) 
     { 
      Container = container; 
     } 

     public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) 
     { 
      return Container.GetService(bundle.JobDetail.JobType) as IJob; 
     } 

     public void ReturnJob(IJob job) 
     { 
      (job as IDisposable)?.Dispose(); 
     } 
    } 

Startup.cs

public void Configure(IApplicationBuilder app, 
      IHostingEnvironment env, 
      ILoggerFactory loggerFactory, 
      IApplicationLifetime lifetime, 
      IServiceProvider container) 
     { 
      loggerFactory.AddConsole(Configuration.GetSection("Logging")); 
      loggerFactory.AddDebug(); 

      app.UseMvc(); 

      // the following 3 lines hook QuartzStartup into web host lifecycle 
      var quartz = new QuartzStartup(container); 
      lifetime.ApplicationStarted.Register(quartz.Start); 
      lifetime.ApplicationStopping.Register(quartz.Stop); 
     } 

QuartzStartup.cs

public class QuartzStartup 
    { 
     private IScheduler _scheduler; // after Start, and until shutdown completes, references the scheduler object 
     private readonly IServiceProvider container; 

     public QuartzStartup(IServiceProvider container) 
     { 
      this.container = container; 
     } 

     // starts the scheduler, defines the jobs and the triggers 
     public void Start() 
     { 
      if (_scheduler != null) 
      { 
       throw new InvalidOperationException("Already started."); 
      } 

      var schedulerFactory = new StdSchedulerFactory(); 
      _scheduler = schedulerFactory.GetScheduler().Result; 
      _scheduler.JobFactory = new JobFactory(container); 
      _scheduler.Start().Wait(); 

      var voteJob = JobBuilder.Create<VoteJob>() 
       .Build(); 

      var voteJobTrigger = TriggerBuilder.Create() 
       .StartNow() 
       .WithSimpleSchedule(s => s 
        .WithIntervalInSeconds(60) 
        .RepeatForever()) 
       .Build(); 

      _scheduler.ScheduleJob(voteJob, voteJobTrigger).Wait(); 
     } 

     // initiates shutdown of the scheduler, and waits until jobs exit gracefully (within allotted timeout) 
     public void Stop() 
     { 
      if (_scheduler == null) 
      { 
       return; 
      } 

      // give running jobs 30 sec (for example) to stop gracefully 
      if (_scheduler.Shutdown(waitForJobsToComplete: true).Wait(30000)) 
      { 
       _scheduler = null; 
      } 
      else 
      { 
       // jobs didn't exit in timely fashion - log a warning... 
      } 
     } 
    } 

귀하의 서비스를 컨테이너 (제 경우에는 VoteJob)에 등록해야한다고 생각하십시오.
이 내용은 answer을 기반으로 구현됩니다.
도움이되기를 바랍니다.

0

같은 문제가 있습니다.

services.AddScoped<IJob, HelloJob>();

에서

services.AddScoped<HelloJob>();

I 업데이트 후 작동합니다.

_factory.GetService(bundle.JobDetail.JobType) as IJob; null이 아님 :