Topshelf+Quartz在.Net Core框架下的實現

  在我們日常開發工作中,經常會運用到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;
        }
    }

  

  項目結構截圖

附項目源碼 https://gitee.com/gt1987/gt.dotnetcore

原文出處:https://www.cnblogs.com/gt1987/p/11806053.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章