• 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

  • 相关阅读:
    .Net中的装箱和拆箱
    使用GetThumbnailImage进行图片缩放操作
    潭州课堂25班:Ph201805201 第二课:数据类型和序列类型 (课堂笔记)
    公开课 之 心蓝 数据分析 (课堂笔记)
    潭州课堂25班:Ph201805201 第一课:环境搭建 (课堂笔记)
    Maven笔记
    java中Swing编程再度练习篇
    Swing编程练习。可能这篇会有错误哦
    Swing
    Swing编程把图片放入frame里。先不作为背景图片
  • 原文地址:https://www.cnblogs.com/gt1987/p/11806053.html
Copyright © 2020-2023  润新知