【C#】Quartz.NET怎么动态调用方法,并且根据指定时间周期执行,动态配置类何方法以及Cron表达式,有请DeepSeek_c# quartz
🌹欢迎来到《小5讲堂》🌹
🌹这是《C#》系列文章,每篇文章将以博主理解的角度展开讲解。🌹
🌹温馨提示:博主能力有限,理解水平有限,若有不对之处望指正!🌹
目录
- 前言
- 效果
- Quartz.NET插件
- 推荐文章
前言
任务调度一直都有在用,但是自己确实没有从零开始搭建何尝试创建,
最近有伙伴咨询任务调度怎么使用,因此自己也尝试了一边搭建,好在现在有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);
注意事项
- 类型解析:确保
Type.GetType()
能找到你的类,可能需要使用程序集限定名称 - 依赖注入:如果需要使用DI容器创建实例,可以修改作业工厂
- 异常处理:确保作业中的异常被适当处理
- 生命周期:长时间运行的应用需要注意调度器的生命周期管理
- 日志记录:建议添加日志记录以便调试
这样实现后,你的类库就提供了一个完整的、可动态调度方法的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#】使用代码实现龙年春晚扑克牌魔术(守岁共此时),流程描述篇