在我们日常开发工作中,经常会运用到Quartz+Topshelf组件的组合来开发一些定时任务。那么在.Net Core下如何去使用呢?我自己尝试搭建了一个测试项目,过程中遇到了以下一些问题:

  • Quartz 配置文件及版本问题。我们知道Quartz有2个配置文件,quartz.config和quartz.job.xml。前者负责组件初始化配置,后者负责job和triggle的配置。刚开始我是直接把framework下的配置文件直接拿过来用的,启动直接报错。主要问题在quartz.config
    quartz.plugin.xml.type = Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz
    

    这一段上。原因Quartz最新版本已经将Plugin模块单独剥离出一个独立的DLL,这里的引用也要变化。需要Nuget上下载Quartz.Plugins组件,并将上一段改成

    quartz.plugin.xml.type = Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz.Plugins
    

     

  • DI问题。为了贴合.Net Core DI精神,我们也要来实现Console程序的DI功能。第一个问题是Job如何DI?首先我们需要自己去实现JobFactory

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

      注入方式

    IServiceCollection services = new ServiceCollection();
    services.AddScoped<IJobFactory, NewJobFactory>();
    services.AddSingleton(service =>
    {
         var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result;
         scheduler.JobFactory = service.GetService<IJobFactory>();
         return scheduler;
    });

     

  • Console程序的配置文件获取以及注入问题。众所周知,.Net Core下建立的Console程序就是一块白板,什么都没有。配置文件我们还得自己去建一个.json文件。并且需要自己从Nuget上下载的组件包(见后面项目结构截图)。加载方式如下
  •         private IConfiguration ConfigureConfiguration()
            {            
                //配置文件
                var builder = new ConfigurationBuilder()
                    .SetBasePath(Directory.GetCurrentDirectory())
                    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
                return builder.Build();
            }
    

      注入方式如下

                if (configuration != null)
                {
                    //iconfiguration注入
                    services.AddSingleton<IConfiguration>(configuration);
                }
    
                //自定义 option方式注入
                services.Configure<AppSetting>(configuration);
    

      这样就可以在后续的类代码中 直接通过DI方式获取IConfiguration对象或者你自己的Option对象了

  贴上完整代码。

  Program.cs

        static void Main(string[] args)
        {
            HostFactory.Run(x =>
            {
                x.Service<ServiceRunner>();
                x.SetDescription("gt.dotnetcore.consolesample");
                x.SetDisplayName("gt.dotnetcore.consolesample");
                x.SetServiceName("gt.dotnetcore.consolesample");

                x.StartAutomatically();
            });
        }

  ServiceRunner.cs 启动的核心

    public class ServiceRunner : ServiceControl
    {
        //private readonly IScheduler _scheduler;

        private IServiceProvider _serviceProvider;
        public ServiceRunner()
        {
            var configurationRoot = ConfigureConfiguration();
            _serviceProvider = ConfigureServices(configurationRoot);
        }

        private IConfiguration ConfigureConfiguration()
        {            
            //配置文件
            var builder = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
            return builder.Build();
        }
        private IServiceProvider ConfigureServices(IConfiguration configuration)
        {
            //依赖注入
            IServiceCollection services = new ServiceCollection();
            //后续需要使用log的话,这里需要注入
            services.AddTransient<ILoggerFactory, LoggerFactory>();
            services.AddTransient<ITest, TestBiz>();
            services.AddScoped<IJobFactory, NewJobFactory>();
            if (configuration != null)
            {
                //iconfiguration注入
                services.AddSingleton<IConfiguration>(configuration);
            }

            //自定义 option方式注入
            services.Configure<AppSetting>(configuration);
            //这里注意Job的注入方式,不要强制指定IJob实现方式!!
            services.AddScoped<TestJob>();
            services.AddScoped<Test2Job>();
            services.AddSingleton(service =>
            {
                var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result;
                scheduler.JobFactory = service.GetService<IJobFactory>();
                return scheduler;
            });
            //构建容器
            return services.BuildServiceProvider();
        }

        public bool Start(HostControl hostControl)
        {
            var scheduler = _serviceProvider.GetService(typeof(IScheduler)) as IScheduler;
            scheduler.Start();
            return true;
        }

        public bool Stop(HostControl hostControl)
        {
            var scheduler = _serviceProvider.GetService(typeof(IScheduler)) as IScheduler;
            scheduler.Shutdown(true);
            return true;
        }
    }

  Test2Job.cs

    public class Test2Job : IJob
    {
        private ITest _testService;
        private AppSetting _appsetting;
        private IConfiguration _configuration;

        public Test2Job(ITest testService, IOptionsMonitor<AppSetting> appSettingAccessor, IConfiguration configuration)
        {
            _testService = testService;
            _appsetting = appSettingAccessor.CurrentValue;
            _configuration = configuration;
        }
        public Task Execute(IJobExecutionContext context)
        {
            Console.WriteLine($"job2222222222222 started:{_appsetting.TestCN}");
            var t = _testService.Dowork(1);
            t.Wait();
            Console.WriteLine($"job2222222222222 ended:{_configuration["TestCN"]}");

            return Task.CompletedTask;
        }
    }

  

  项目结构截图

版权声明:本文为gt1987原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/gt1987/p/11806053.html