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

news2025/6/7 4:20:44

🌹欢迎来到《小5讲堂》🌹
🌹这是《C#》系列文章,每篇文章将以博主理解的角度展开讲解。🌹
🌹温馨提示:博主能力有限,理解水平有限,若有不对之处望指正!🌹

在这里插入图片描述

目录

  • 前言
  • 效果
  • Quartz.NET插件
    • 1. 创建调度服务类
    • 2. 实现动态方法作业
    • 3. 在类库中暴露启动接口
    • 4. 使用示例
      • 在类库中定义要调用的方法
      • 在主程序中调用类库
    • 5.目标任务类
    • 6. 高级配置选项
    • 注意事项
  • 推荐文章

前言

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

效果

设置每隔10秒执行一次
在这里插入图片描述

Quartz.NET插件

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

1. 创建调度服务类

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

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. 实现动态方法作业

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

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. 在类库中暴露启动接口

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

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. 使用示例

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

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

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

在主程序中调用类库

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.目标任务类

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

// 在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中处理参数:

// 修改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#】使用代码实现龙年春晚扑克牌魔术(守岁共此时),流程描述篇

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2402452.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

02 Deep learning神经网络的编程基础 逻辑回归--吴恩达

逻辑回归 逻辑回归是一种用于解决二分类任务&#xff08;如预测是否是猫咪等&#xff09;的统计学习方法。尽管名称中包含“回归”&#xff0c;但其本质是通过线性回归的变体输出概率值&#xff0c;并使用Sigmoid函数将线性结果映射到[0,1]区间。 以猫咪预测为例 假设单个样…

MySQL的并发事务问题及事务隔离级别

一、并发事务问题 1). 赃读&#xff1a;一个事务读到另外一个事务还没有提交的数据。 比如 B 读取到了 A 未提交的数据。 2). 不可重复读&#xff1a;一个事务先后读取同一条记录&#xff0c;但两次读取的数据不同&#xff0c;称之为不可重复读。 事务 A 两次读取同一条记录&…

ProfiNet 分布式 IO 在某污水处理厂的应用

随着城市化进程的加速&#xff0c;污水处理厂的规模和复杂性不断增加&#xff0c;对自动化控制系统的要求也越来越高。PROfinet 分布式 IO 作为一种先进的工业通信技术&#xff0c;以其高速、可靠、灵活的特性&#xff0c;为污水处理厂的自动化升级提供了有力支持。本文将结合某…

vue2 , el-select 多选树结构,可重名

人家antd都支持&#xff0c;elementplus 也支持&#xff0c;vue2的没有&#xff0c;很烦。 网上其实可以搜到各种的&#xff0c;不过大部分不支持重名&#xff0c;在删除的时候可能会删错&#xff0c;比如树结构1F的1楼啊&#xff0c;2F的1楼啊这种同时勾选的情况。。 可以全…

Excel处理控件Aspose.Cells教程:使用 C# 从 Excel 进行邮件合并

邮件合并功能让您能够轻松批量创建个性化文档&#xff0c;例如信函、电子邮件、发票或证书。您可以从模板入手&#xff0c;并使用电子表格中的数据进行填充。Excel 文件中的每一行都会生成一个新文档&#xff0c;并在正确的位置包含正确的详细信息。这是一种自动化重复性任务&a…

EXCEL通过DAX Studio获取端口号连接PowerBI

EXCEL通过DAX Studio获取端口号连接PowerBI 昨天我分享了EXCEL链接模板是通过获取端口号和数据库来连接PowerBI模型的&#xff0c;链接&#xff1a;浅析EXCEL自动连接PowerBI的模板&#xff0c;而DAX Studio可以获取处于打开状态的PowerBI的端口号。 以一个案例分享如何EXCEL…

C# 委托UI控件更新例子,何时需要使用委托

1. 例子1 private void UdpRxCallBackFunc(UdpDataStruct info) {// 1. 前置检查防止无效调用if (textBoxOutput2.IsDisposed || !textBoxOutput2.IsHandleCreated)return;// 2. 使用正确的委托类型Invoke(new Action(() >{// 3. 双重检查确保安全if (textBoxOutput2.IsDis…

大模型数据流处理实战:Vue+NDJSON的Markdown安全渲染架构

在Vue中使用HTTP流接收大模型NDJSON数据并安全渲染 在构建现代Web应用时&#xff0c;处理大模型返回的流式数据并安全地渲染到页面是一个常见需求。本文将介绍如何在Vue应用中通过普通HTTP流接收NDJSON格式的大模型响应&#xff0c;使用marked、highlight.js和DOMPurify等库进…

python项目如何创建docker环境

这里写自定义目录标题 python项目创建docker环境docker配置国内镜像源构建一个Docker 镜像验证镜像合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPant…

PyTorch--池化层(4)

池化层&#xff08;Pooling Layer&#xff09; 用于降低特征图的空间维度&#xff0c;减少计算量和参数数量&#xff0c;同时保留最重要的特征信息。 池化作用&#xff1a;比如1080p视频——720p 池化层的步长默认是卷积核的大小 ceil 允许有出界部分&#xff1b;floor 不允许…

2025年大模型平台落地实践研究报告|附75页PDF文件下载

本报告旨在为各行业企业在建设落地大模型平台的过程中&#xff0c;提供有效的参考和指引&#xff0c;助力大模型更高效更有价值地规模化落地。本报告系统性梳理了大模型平台的发展背景、历程和现状&#xff0c;结合大模型平台的特点提出了具体的落地策略与路径&#xff0c;同时…

PPTAGENT:让PPT生成更智能

想要掌握如何将大模型的力量发挥到极致吗&#xff1f;叶梓老师带您深入了解 Llama Factory —— 一款革命性的大模型微调工具。 1小时实战课程&#xff0c;您将学习到如何轻松上手并有效利用 Llama Factory 来微调您的模型&#xff0c;以发挥其最大潜力。 CSDN教学平台录播地址…

《汇编语言》第13章 int指令

中断信息可以来自 CPU 的内部和外部&#xff0c;当 CPU 的内部有需要处理的事情发生的时候&#xff0c;将产生需要马上处理的中断信息&#xff0c;引发中断过程。在第12章中&#xff0c;我们讲解了中断过程和两种内中断的处理。 这一章中&#xff0c;我们讲解另一种重要的内中断…

Redis实战-基于redis和lua脚本实现分布式锁以及Redission源码解析【万字长文】

前言&#xff1a; 在上篇博客中&#xff0c;我们探讨了单机模式下如何通过悲观锁&#xff08;synchronized&#xff09;实现"一人一单"功能。然而&#xff0c;在分布式系统或集群环境下&#xff0c;单纯依赖JVM级别的锁机制会出现线程并发安全问题&#xff0c;因为这…

计算机网络 : 应用层自定义协议与序列化

计算机网络 &#xff1a; 应用层自定义协议与序列化 目录 计算机网络 &#xff1a; 应用层自定义协议与序列化引言1. 应用层协议1.1 再谈协议1.2 网络版计算器1.3 序列化与反序列化 2. 重新理解全双工3. socket和协议的封装4. 关于流失数据的处理5. Jsoncpp5.1 特性5.2 安装5.3…

Python Day42 学习(日志Day9复习)

补充&#xff1a;关于“箱线图”的阅读 以下图为例 浙大疏锦行 箱线图的基本组成 箱体&#xff08;Box&#xff09;&#xff1a;中间的矩形&#xff0c;表示数据的中间50%&#xff08;从下四分位数Q1到上四分位数Q3&#xff09;。中位线&#xff08;Median&#xff09;&#…

CMake在VS中使用远程调试

选中CMakeLists.txt, 右键-添加调试配置-选中"C\C远程windows调试" 之后将 aunch.vs.json文件改为如下所示: CMake在VS中使用远程调试时,Launch.vs.json中远程调试设置 ,远程电脑开启VS专用的RemoteDebugger {"version": "0.2.1","defaul…

《图解技术体系》How Redis Architecture Evolves?

Redis架构的演进经历了多个关键阶段&#xff0c;从最初的内存数据库发展为支持分布式、多模型和持久化的高性能系统。以下为具体演进路径&#xff1a; 单线程模型与基础数据结构 Redis最初采用单线程架构&#xff0c;利用高效的I/O多路复用&#xff08;如epoll&#xff09;处…

一文速通Python并行计算:12 Python多进程编程-进程池Pool

一文速通 Python 并行计算&#xff1a;12 Python 多进程编程-进程池 Pool 摘要&#xff1a; 在Python多进程编程中&#xff0c;Pool类用于创建进程池&#xff0c;可并行执行多个任务。通过map、apply等方法&#xff0c;将函数和参数分发到子进程&#xff0c;提高CPU利用率&…

Web前端之原生表格动态复杂合并行、Vue

MENU 效果公共数据纯原生StyleJavaScript vue原生table 效果 原生的JavaScript原生table null 公共数据 const list [{id: "a1",title: "第一列",list: [{id: "a11",parentId: "a1",title: "第二列",list: [{ id: "…