【C#】Quartz.NET怎么动态调用方法,并且根据指定时间周期执行,动态配置类何方法以及Cron表达式,有请DeepSeek

🌹欢迎来到《小5讲堂》🌹

🌹这是《C#》系列文章,每篇文章将以博主理解的角度展开讲解。🌹

🌹温馨提示:博主能力有限,理解水平有限,若有不对之处望指正!🌹

目录

前言

任务调度一直都有在用,但是自己确实没有从零开始搭建何尝试创建,

最近有伙伴咨询任务调度怎么使用,因此自己也尝试了一边搭建,好在现在有AI工具,简单问一句就能出来我想要的效果,一起来看看吧。

效果

设置每隔10秒执行一次

Quartz.NET插件

要在类库中启动Quartz.NET动态调度功能,你需要创建一个可被主程序调用的入口点。以下是完整的实现方案:

1. 创建调度服务类

在你的类库中创建一个调度服务类,封装所有调度逻辑:

csharp 复制代码
using Quartz;
using Quartz.Impl;
using System;
using System.Collections.Specialized;
using System.Threading.Tasks;

public class DynamicSchedulerService
{
    private IScheduler _scheduler;

    public async Task StartAsync()
    {
        // 1. 创建调度器
        var factory = new StdSchedulerFactory(GetSchedulerProperties());
        _scheduler = await factory.GetScheduler();

        // 2. 启动调度器
        await _scheduler.Start();
    }

    public async Task StopAsync()
    {
        if (_scheduler != null)
        {
            await _scheduler.Shutdown();
        }
    }

    public async Task ScheduleMethodAsync(
        string methodName,
        string className,
        string cronExpression,
        string jobName = null,
        string groupName = "default")
    {
        if (_scheduler == null)
        {
            throw new InvalidOperationException("调度器未启动,请先调用StartAsync()");
        }

        jobName ??= $"job_{methodName}_{Guid.NewGuid().ToString("N")}";

        // 创建作业
        var job = JobBuilder.Create<DynamicMethodJob>()
            .WithIdentity(jobName, groupName)
            .UsingJobData("MethodName", methodName)
            .UsingJobData("ClassName", className)
            .Build();

        // 创建触发器
        var trigger = TriggerBuilder.Create()
            .WithIdentity($"trigger_{jobName}", groupName)
            .WithCronSchedule(cronExpression)
            .Build();

        // 安排作业
        await _scheduler.ScheduleJob(job, trigger);
    }

    private NameValueCollection GetSchedulerProperties()
    {
        // 可以在这里配置线程池、作业存储等设置
        return new NameValueCollection
        {
            // 示例配置,根据需求调整
            ["quartz.threadPool.threadCount"] = "10",
            ["quartz.scheduler.instanceName"] = "DynamicScheduler"
        };
    }
}

2. 实现动态方法作业

在类库中创建动态方法作业类:

csharp 复制代码
using Quartz;
using System;
using System.Reflection;
using System.Threading.Tasks;

public class DynamicMethodJob : IJob
{
    public Task Execute(IJobExecutionContext context)
    {
        try
        {
            var dataMap = context.JobDetail.JobDataMap;
            var typeName = dataMap.GetString("ClassName");
            var methodName = dataMap.GetString("MethodName");

            if (string.IsNullOrEmpty(typeName) || string.IsNullOrEmpty(methodName))
            {
                throw new ArgumentException("ClassName和MethodName不能为空");
            }

            var type = Type.GetType(typeName);
            if (type == null)
            {
                throw new TypeLoadException($"无法加载类型: {typeName}");
            }

            var method = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
            if (method == null)
            {
                throw new MissingMethodException($"在类型{typeName}中找不到方法{methodName}");
            }

            object instance = null;
            if (!method.IsStatic)
            {
                instance = Activator.CreateInstance(type);
            }

            // 调用方法
            method.Invoke(instance, null);

            return Task.CompletedTask;
        }
        catch (Exception ex)
        {
            // 记录日志或处理异常
            Console.WriteLine($"作业执行失败: {ex}");
            throw new JobExecutionException(ex);
        }
    }
}

3. 在类库中暴露启动接口

创建一个公共接口供外部调用:

csharp 复制代码
public interface IDynamicScheduler
{
    Task StartSchedulerAsync();
    Task StopSchedulerAsync();
    Task ScheduleMethodAsync(string methodName, string className, string cronExpression, string jobName = null, string groupName = "default");
}

public class DynamicScheduler : IDynamicScheduler
{
    private readonly DynamicSchedulerService _schedulerService = new DynamicSchedulerService();

    public Task StartSchedulerAsync() => _schedulerService.StartAsync();
    public Task StopSchedulerAsync() => _schedulerService.StopAsync();
    
    public Task ScheduleMethodAsync(string methodName, string className, string cronExpression, string jobName = null, string groupName = "default")
    {
        return _schedulerService.ScheduleMethodAsync(methodName, className, cronExpression, jobName, groupName);
    }
}

4. 使用示例

在类库中定义要调用的方法

csharp 复制代码
public class SampleTasks
{
    public static void SendDailyReport()
    {
        Console.WriteLine($"{DateTime.Now}: 正在发送每日报告...");
        // 实际发送报告的逻辑
    }

    public void ProcessData()
    {
        Console.WriteLine($"{DateTime.Now}: 正在处理数据...");
        // 实际处理数据的逻辑
    }
}

在主程序中调用类库

csharp 复制代码
using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using TaskV2.Base;

namespace TaskV2
{
    public class Program
    {
        static async Task Main(string[] args)
        {
            // 创建调度器实例
            IDynamicScheduler scheduler = new DynamicScheduler();

            try
            {
                // 启动调度器
                await scheduler.StartSchedulerAsync();
                Console.WriteLine("调度器已启动");

                /*
                // 调度静态方法 - 每天上午9点执行
                await scheduler.ScheduleMethodAsync(
                    "SendDailyReport",
                    "YourNamespace.SampleTasks", // 完整类名(包括命名空间)
                    "0 0 9 * * ?"); // 每天9点
                */

                /*
                // 调度实例方法 - 每30分钟执行一次
                await scheduler.ScheduleMethodAsync(
                    "ProcessData",
                    "YourNamespace.SampleTasks",
                    "0 0/30 * * * ?");
                */

                // 查询表 - 执行
                List<JobModel> list = new List<JobModel>();
                list.Add(new JobModel()
                {
                    methodName = "TestData",
                    className = "TaskV2.Work.AccessTokenShop",
                    cronExpression = "0/10 * * * * ?",
                });

                // 调度实例方法
                foreach (JobModel obj in list)
                {
                    await scheduler.ScheduleMethodAsync(
                        obj.methodName,
                        obj.className,
                        obj.cronExpression);
                }


                Console.WriteLine("按任意键停止...");
                Console.ReadKey();
            }
            finally
            {
                // 停止调度器
                await scheduler.StopSchedulerAsync();
                Console.WriteLine("调度器已停止");
            }
        }
    }
}

5.目标任务类

csharp 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TaskV2.Work
{
    public class AccessTokenShop
    {
        public int Id = 1;
        public void TestData()
        {
            Console.WriteLine($"TestData{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
        }
    }
}

6. 高级配置选项

如果你需要更复杂的配置,可以扩展DynamicSchedulerService

csharp 复制代码
// 在DynamicSchedulerService类中添加
public async Task ScheduleMethodWithParametersAsync(
    string methodName,
    string className,
    string cronExpression,
    object[] parameters,
    string jobName = null,
    string groupName = "default")
{
    jobName ??= $"job_{methodName}_{Guid.NewGuid().ToString("N")}";

    var job = JobBuilder.Create<DynamicMethodJob>()
        .WithIdentity(jobName, groupName)
        .UsingJobData("MethodName", methodName)
        .UsingJobData("ClassName", className)
        .UsingJobData("Parameters", parameters) // 传递参数
        .Build();

    var trigger = TriggerBuilder.Create()
        .WithIdentity($"trigger_{jobName}", groupName)
        .WithCronSchedule(cronExpression)
        .Build();

    await _scheduler.ScheduleJob(job, trigger);
}

然后在DynamicMethodJob中处理参数:

csharp 复制代码
// 修改DynamicMethodJob的Execute方法
var parameters = context.JobDetail.JobDataMap.Get("Parameters") as object[];
method.Invoke(instance, parameters);

注意事项

  1. 类型解析 :确保Type.GetType()能找到你的类,可能需要使用程序集限定名称
  2. 依赖注入:如果需要使用DI容器创建实例,可以修改作业工厂
  3. 异常处理:确保作业中的异常被适当处理
  4. 生命周期:长时间运行的应用需要注意调度器的生命周期管理
  5. 日志记录:建议添加日志记录以便调试

这样实现后,你的类库就提供了一个完整的、可动态调度方法的Quartz.NET解决方案,可以在任何.NET应用程序中使用。

推荐文章

【C#】Quartz.NET怎么动态调用方法,并且根据指定时间周期执行,动态配置类何方法以及Cron表达式,有请DeepSeek

【C#】.net core6.0无法访问到控制器方法,直接404。由于自己的不仔细,出现个低级错误,这让DeepSeek看出来了,是什么错误呢,来瞧瞧

【C#】Html转Pdf,Spire和iTextSharp结合,.net framework 4.8

【C#】事务(进程 ID 64)与另一个进程被死锁在锁资源上,并且已被选作死锁牺牲品。请重新运行该事务。不能在具有唯一索引"XXX_Index"的对象"dbo.Test"中插入重复键的行。

【C#】使用DeepSeek帮助评估数据库性能问题,C# 使用定时任务,每隔一分钟移除一次表,再重新创建表,和往新创建的表追加5万多条记录

【C#】合理使用DeepSeek相关AI应用为我们提供强有力的开发工具,在.net core 6.0框架下使用JsonNode动态解析json字符串,如何正确使用单问号和双问号做好空值处理

【C#】已经实体类和动态实体类的反射使用方法,两分钟回顾,码上就懂

【C#】使用vue3的axios发起get和post请求.net framework部署的API显示跨域

【C#】.net core 6.0 webapi 使用core版本的NPOI的Excel读取数据以及保存数据

【C#】pdf按页分割文件,以及分页合并,效果还不错,你值得拥有

【C#】未能加载文件或程序集"CefSharp.Core.Runtime.dll"或它的某一个依赖项。找不到指定的模块。

【C#】.net core 6.0 在program时间格式统一json格式化,并列举program默认写法和简化写法

【C#】.net core 6.0 ApiController,API控制器方法,API接口以实体类作为接收参数应该注意的点

【C#】 SortedDictionary,查找字典中是否存在给定的关键字

【C#】.net core 6.0 MVC返回JsonResult显示API接口返回值不可被JSON反序列化

【C#】.net core 6.0 使用第三方日志插件Log4net,配置文件详细说明

【C#】使用代码实现龙年春晚扑克牌魔术(守岁共此时),代码实现篇

【C#】使用代码实现龙年春晚扑克牌魔术(守岁共此时),流程描述篇

相关推荐
czfeixiang10 分钟前
专注于PLC数据采集MES交互解决方案
mcu·.net·mes
追逐时光者1 小时前
Visual Studio 2022 中的 EF Core 反向工程和模型可视化扩展插件
.net·visual studio
刚子编程1 小时前
C# WinForms 实现打印监听组件
开发语言·c#·winform·打印监听组件
时央1234562 小时前
C#使用Tuple方法实现OpreateResultModel功能
运维·开发语言·c#
z2014z3 小时前
第1章 C# 和 .NET 框架 笔记
笔记·c#·.net
摘星编程4 小时前
华为云Flexus+DeepSeek征文 | 模型即服务(MaaS)安全攻防:企业级数据隔离方案
大数据·人工智能·安全·华为云·deepseek
lph19724 小时前
csharp设计方法
c#
JNU freshman5 小时前
windows 开发
windows·c#
Kookoos5 小时前
ABP vNext 多语言与本地化:动态切换、资源继承与热更新
后端·.net·abp vnext
MasterNeverDown12 小时前
在C#中的乐观锁和悲观锁
c#·并发·