.Net Core 3.1 +Topshelf+Quartz创建Windows定时任务

准备工作

  • 创建.net core 控制台应用程序,这里不做过多介绍
  • 添加TopShelf包:TopShelf;
  • 添加Quartz包:Quartz、Quartz.Plugins;
  • 添加依赖注入包:Microsoft.Extensions.DependencyInjection;
  • 添加读取配置文件包:Microsoft.Extensions.Configuration.Json;
  • 添加访问数据库包:Microsoft.EntityFrameworkCore;

配置Quartz

  • 创建appsettings.json文件,右键文件属性,并更改属性为始终复制 内容
    {
    "quartz": {
        "scheduler": {
          "instanceName": "Job"
        },
        "threadPool": {
          "type": "Quartz.Simpl.SimpleThreadPool, Quartz",
          "threadPriority": "Normal",
          "threadCount": 10
        },
        "plugin": {
          "jobInitializer": {
            "type": "Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz.Plugins",
            "fileNames": "quartz_jobs.xml"
          }
        }
      }
    }
    

     

  • 创建QuartzOption 类
        public class QuartzOption
        {
            public QuartzOption(IConfiguration config)
            {
                if (config == null)
                {
                    throw new ArgumentNullException(nameof(config));
                }
    
                var section = config.GetSection("quartz");
                section.Bind(this);
            }
    
            public Scheduler Scheduler { get; set; }
    
            public ThreadPool ThreadPool { get; set; }
    
            public Plugin Plugin { get; set; }
    
            public NameValueCollection ToProperties()
            {
                var properties = new NameValueCollection
                {
                    ["quartz.scheduler.instanceName"] = Scheduler?.InstanceName,
                    ["quartz.threadPool.type"] = ThreadPool?.Type,
                    ["quartz.threadPool.threadPriority"] = ThreadPool?.ThreadPriority,
                    ["quartz.threadPool.threadCount"] = ThreadPool?.ThreadCount.ToString(),
                    ["quartz.plugin.jobInitializer.type"] = Plugin?.JobInitializer?.Type,
                    ["quartz.plugin.jobInitializer.fileNames"] = Plugin?.JobInitializer?.FileNames
                };
    
                return properties;
            }
        }
    
        public class Scheduler
        {
            public string InstanceName { get; set; }
        }
    
        public class ThreadPool
        {
            public string Type { get; set; }
    
            public string ThreadPriority { get; set; }
    
            public int ThreadCount { get; set; }
        }
    
        public class Plugin
        {
            public JobInitializer JobInitializer { get; set; }
        }
    
        public class JobInitializer
        {
            public string Type { get; set; }
            public string FileNames { get; set; }
        }
    
    

      

  • 添加一个Job

    public class TestJob : IJob
        {
            private readonly IService _service;
    
            public SyncJob(IService service)
            {
                _service = service;
            }
    
            public async Task Execute(IJobExecutionContext context)
            {
                Log.Information("同步开始...");
                _service.DoSomeThing();
            }
        }
    

      

  • 实现IJobFactory

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

      

  • 创建Quartz调度的配置文件 quartz_jobs.xml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <!-- This file contains job definitions in schema version 2.0 format -->
    
    <job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0">
    
      <processing-directives>
        <overwrite-existing-data>true</overwrite-existing-data>
      </processing-directives>
    
        <schedule>
          <!--TestJob测试 任务配置-->
          <job>
            <name>TestJob</name>
            <group>ServerGroup</group>
            <description>上传视频</description>
            <job-type>Server.TestJob, Server</job-type>
            <durable>true</durable>
            <recover>false</recover>
          </job>
          <trigger>
            <cron>
              <name>TestJobTrigger</name>
              <group>ServerGroup</group>
              <job-name>TestJob</job-name>
              <job-group>ServerGroup</job-group>
              <cron-expression>0/60 * * * * ?</cron-expression>
            </cron>
          </trigger>
    
          <!--TestJob2测试 任务配置-->
          <!--
        <job>
          <name>TestJob2</name>
          <group>Test</group>
          <description>TestJob2测试</description>
          <job-type>CoreSolution.Job.jobs.TestJob2,CoreSolution.Job</job-type>
          <durable>true</durable>
          <recover>false</recover>
        </job>
        <trigger>
          <cron>
            <name>TestJob2Trigger</name>
            <group>Test</group>
            <job-name>TestJob2</job-name>
            <job-group>Test</job-group>
            <cron-expression>0/30 * * * * ?</cron-expression>
            -->
          <!--30s执行一次-->
          <!--
          </cron>
        </trigger>-->
    
        </schedule>
      </job-scheduling-data>
    

      

  • 添加一个类,此类用户服务启动调用

  • public sealed class ServiceRunner : ServiceControl, ServiceSuspend
        {
            //调度器
            private readonly IScheduler scheduler;
            public ServiceRunner()
            {
    
                scheduler = StdSchedulerFactory.GetDefaultScheduler().GetAwaiter().GetResult();
    
            }
            //开始
            public bool Start(HostControl hostControl)
            {
                scheduler.Start();
                return true;
            }
            //停止
            public bool Stop(HostControl hostControl)
            {
                scheduler.Shutdown(false);
                return true;
            }
            //恢复所有
            public bool Continue(HostControl hostControl)
            {
                scheduler.ResumeAll();
                return true;
            }
            //暂停所有
            public bool Pause(HostControl hostControl)
            {
                scheduler.PauseAll();
                return true;
            }
        }
    

      

  • 配置TopShelf

    class Program
        {
            static void Main(string[] args)
            {
                var rc = HostFactory.Run(x =>
                {
                   x.Service<ServiceRunner>(s => {
                        s.ConstructUsing(name => new ServiceRunner());
                        s.WhenStarted((tc, hc) => tc.Start(hc));
                        s.WhenStopped((tc, hc) => tc.Stop(hc));
                        s.WhenContinued((tc, hc) => tc.Continue(hc));
                        s.WhenPaused((tc, hc) => tc.Pause(hc));
                    });
    
                    x.RunAsLocalService();
                    x.StartAutomaticallyDelayed();
                    x.RunAsLocalSystem();
    
                    x.SetDescription("测试后台服务");
                    x.SetDisplayName("TestServer");
                    x.SetServiceName("TestServer");
                    x.EnablePauseAndContinue();
                });
                var exitCode = (int)Convert.ChangeType(rc, rc.GetTypeCode());
                Environment.ExitCode = exitCode;
            }
        }
    

      

原文地址:https://www.cnblogs.com/DavidAi/p/13685431.html