石英。Net依赖注入。Net核心

时间:2022-04-03 02:14:22

In my project I have to use Quartz but I don't know what i do wrong.

在我的项目中,我必须使用石英,但我不知道我做错了什么。

JobFactory:

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:

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

And when I try run my Job (class have dependency injection) i always get Exception becouse:

当我尝试运行我的工作(类有依赖注入),我总是得到例外,因为:

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

is always null.

总是空。

My class implement IJob and in startup.cs I add:

我的类实现IJob和startup。cs我添加:

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

and

app.UseQuartz();

I using standard .net Core dependency injection:

我使用标准的。net核心依赖注入:

using Microsoft.Extensions.DependencyInjection;

3 个解决方案

#1


2  

This is how I did it in my application. Instead of adding the Scheduler to the ioc I only add the factory

这就是我在我的申请中所做的。我只添加了工厂,而不是向ioc添加调度器。

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

My job factory pretty much looks the same. Transient does not really matter as I only use this once anyway. My use Quartz extension method then is

我的工作工厂看起来差不多是一样的。瞬变并不重要,因为我只使用一次。我用的是石英扩展法。

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

The Quartz class is Singleton as well.

Quartz类也是单例的。

#2


2  

This is just a simple sample of my solution to solve IoC problem:

这只是我解决IoC问题的一个简单示例:

JobFactory.cs

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

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

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

consider that you should register your service into the container (in my case VoteJob) in advance.
I implement this based on this answer.
I hope it can be helpful.

考虑一下,您应该提前将服务注册到容器中(在我的案例中是VoteJob)。我基于这个答案实现这个。我希望它能有所帮助。

#3


2  

I got the same issue.

我也有同样的问题。

I update from

我更新

services.AddScoped<IJob, HelloJob>();

服务。AddScoped < IJob HelloJob >();

to

services.AddScoped<HelloJob>();

services.AddScoped < HelloJob >();

then it works.

它的工作原理。

_factory.GetService(bundle.JobDetail.JobType) as IJob; will not be null :)

作为IJob _factory.GetService(bundle.JobDetail.JobType);将不为空:)

#1


2  

This is how I did it in my application. Instead of adding the Scheduler to the ioc I only add the factory

这就是我在我的申请中所做的。我只添加了工厂,而不是向ioc添加调度器。

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

My job factory pretty much looks the same. Transient does not really matter as I only use this once anyway. My use Quartz extension method then is

我的工作工厂看起来差不多是一样的。瞬变并不重要,因为我只使用一次。我用的是石英扩展法。

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

The Quartz class is Singleton as well.

Quartz类也是单例的。

#2


2  

This is just a simple sample of my solution to solve IoC problem:

这只是我解决IoC问题的一个简单示例:

JobFactory.cs

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

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

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

consider that you should register your service into the container (in my case VoteJob) in advance.
I implement this based on this answer.
I hope it can be helpful.

考虑一下,您应该提前将服务注册到容器中(在我的案例中是VoteJob)。我基于这个答案实现这个。我希望它能有所帮助。

#3


2  

I got the same issue.

我也有同样的问题。

I update from

我更新

services.AddScoped<IJob, HelloJob>();

服务。AddScoped < IJob HelloJob >();

to

services.AddScoped<HelloJob>();

services.AddScoped < HelloJob >();

then it works.

它的工作原理。

_factory.GetService(bundle.JobDetail.JobType) as IJob; will not be null :)

作为IJob _factory.GetService(bundle.JobDetail.JobType);将不为空:)