基于Asp.Net Core 5.0依赖Quartz.Net框架编写的任务调度web管理平台

  • A+
所属分类:.NET技术
摘要

源码地址: https://github.com/246850/Calamus.TaskScheduler演示地址:http://47.101.47.193:1063/

源码地址: https://github.com/246850/Calamus.TaskScheduler

演示地址:http://47.101.47.193:1063/

基于Asp.Net Core 5.0依赖Quartz.Net框架编写的任务调度web管理平台

 

 

 1、Quartz.NET框架核心类

IScheduler:调度者

IJobDetail:任务

ITrigger:触发器

JobKey:任务/触发器标识

JobDataMap:数据包

2、邮件通知(FluentEmail类库)

_fluentEmail.To(to).Subject(subject).Body(body, true).SendAsync(); 

3、Quartz.NET宿主方式,依靠IHostedService后台服务执行

internal class QuartzHostedService : IHostedService { 	private readonly ISchedulerFactory schedulerFactory; 	private readonly IOptions<QuartzHostedServiceOptions> options; 	private IScheduler scheduler = null!;  	public QuartzHostedService( 		ISchedulerFactory schedulerFactory, 		IOptions<QuartzHostedServiceOptions> options) 	{ 		this.schedulerFactory = schedulerFactory; 		this.options = options; 	}  	public async Task StartAsync(CancellationToken cancellationToken) 	{ 		scheduler = await schedulerFactory.GetScheduler(cancellationToken); 		await scheduler.Start(cancellationToken); 	}  	public Task StopAsync(CancellationToken cancellationToken) 	{ 		return scheduler.Shutdown(options.Value.WaitForJobsToComplete, cancellationToken); 	} } 

4.Asp.Net Core 5.0集成

安装依赖包

Quartz

Quartz.AspNetCore

Quartz.Plugins.TimeZoneConverter

Quartz.Serialization.Json

FluentEmail.Core

FluentEmail.Smtp

Startup

public void ConfigureServices(IServiceCollection services) { 	services.AddControllersWithViews(options => 		{ 			options.Filters.Add<GatewayResultFilterAttribute>();    // 通用执行结果包装处理过滤器 			options.Filters.Add<GlobalExceptionFilterAttribute>();  // 全局异常过滤器 		}) 		.AddJsonOptions(options => 		{ 			options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());  // 日期格式化 		}) 		.AddFluentValidation(config =>  // 请求模型参数验证 		{ 			config.RunDefaultMvcValidationAfterFluentValidationExecutes = true;    // false : 禁止默认模型验证 			config.ValidatorOptions.CascadeMode = CascadeMode.Stop; // 不级联验证,第一个规则错误就停止 			config.RegisterValidatorsFromAssemblyContaining<JobCreateOrUpdateValidator>(); 		}); 	services.AddHostedService<NLogHostService>();   // NLog 关闭服务 	services.AddDistributedMemoryCache();  // 分布式缓存接口 	services.AddSingleton(HtmlEncoder.Create(UnicodeRanges.All));// 解决中文乱码 	services.AddHttpClient();   // IHttpClientFactory  	IConfigurationSection quartzConfiguration = Configuration.GetSection("Quartz"); // Quartz配置节点  	/***********Quartz.NET*********/ 	services.AddTransient<HttpJob>();   // 注册job至容器,必须步骤 	services.AddQuartz(config => 	{ 		config.UseTimeZoneConverter(); 		// 使用MicrosoftDependencyInjectionJobFactory工厂类从 容器 中创建job实例 		config.UseMicrosoftDependencyInjectionJobFactory(options => 		{ 			options.AllowDefaultConstructor = false;    // 禁止使用无参构建函数创建 job 			options.CreateScope = false; 		}); 		config.UseDefaultThreadPool(options => 		{ 			options.MaxConcurrency = 10;    // 最大并发执行线程数 		}); 		config.UsePersistentStore(options => 		{ 			options.UseProperties = false; 			//options.UseBinarySerializer();  // 二进制序列化 			options.UseJsonSerializer();    // json序列化 			options.UseMySql(ado => 			{ 				ado.ConnectionString = quartzConfiguration["Database"]; 				ado.TablePrefix = quartzConfiguration["TablePrefix"];  // 默认值 QRTZ_ 				ado.ConnectionStringName = "Quartz.net"; 			}); 		});  		// 监听器 		config.AddSchedulerListener<DefaultSchedulerListener>(); 		config.AddJobListener<DefaultJobListener>(); 		config.AddTriggerListener<DefaultTriggerListener>();  		// 启动NLog日志文件清除job 		config.ScheduleJob<ClearNLogJob>(trigger => 		{ 			trigger.WithIdentity(NLogJobKey.NameKey, NLogJobKey.GroupKey).StartNow() 			.WithCronSchedule("0 0 0 1/3 * ? ", cron => cron.WithMisfireHandlingInstructionFireAndProceed());    // 从每月1日开始,每3天执行一次 		}, job => 		{ 			job.WithIdentity(NLogJobKey.NameKey, NLogJobKey.GroupKey) 			.StoreDurably(false)     // 是否持久化, 无关联触发器时是否移除,false:移除 			.RequestRecovery()  // 重启后是否恢复任务 			.WithDescription("每3天清空NLog日志文件"); 		}); 	}); 	// IHostedService宿主启动 Quartz服务 services.AddSingleton<IHostedService, QuartzHostedService>() 	services.AddQuartzServer(options => 	{ 		// when shutting down we want jobs to complete gracefully 		options.WaitForJobsToComplete = true;   // 等待任务执行完,再退出 	});  	/***********FluentEmail*********/ 	// 为了将邮件通知配置在job data上, 不使用自带的service注册方式 	//services.AddFluentEmail(quartzConfiguration["Smtp:UserName"], "Quartz.NET任务调度通知") 	//    .AddRazorRenderer() 	//    .AddSmtpSender(quartzConfiguration["Smtp:Host"], Convert.ToInt32(quartzConfiguration["Smtp:Port"]), quartzConfiguration["Smtp:UserName"], quartzConfiguration["Smtp:Password"]); 	services.AddTransient<IFluentEmail>(serviceProvider => 	{ 		IScheduler scheduler = serviceProvider.GetRequiredService<ISchedulerFactory>().GetScheduler().Result;  		JobKey key = new JobKey(EmailJobKeys.NameKey, EmailJobKeys.GroupKey); 		if (!scheduler.CheckExists(key).Result) 		{ 			JobDataMap dataMap = new JobDataMap(); 			dataMap.Put(EmailJobKeys.Host, "smtp.qq.com"); 			dataMap.Put(EmailJobKeys.Port, 587);    // 465端口一直尝试不通过,奇怪 			dataMap.Put(EmailJobKeys.UserName, "[email protected]"); // 作者qq,欢迎骚扰 			dataMap.Put(EmailJobKeys.Password, "cirxjtemuzxycagf"); 			dataMap.Put(EmailJobKeys.To, string.Empty); // 接收者邮件支持多个,以 ; 隔开 			dataMap.Put(EmailJobKeys.NickName, "Quartz.NET任务调度通知"); 			dataMap.Put(EmailJobKeys.CacheExpiry, 30);  // 默认30分钟内只通知一次 			IJobDetail job = JobBuilder.Create<HttpJob>() 				.StoreDurably(true) 				.RequestRecovery() 				.WithDescription("邮件通知配置Job,切勿删除") 				.WithIdentity(key) 				.UsingJobData(dataMap) 				.Build(); 			scheduler.AddJob(job, true);   // 初始化邮件通知配置 		}  		IJobDetail emailJob = scheduler.GetJobDetail(key).Result; 		IFluentEmail fluentEmail = new Email(new ReplaceRenderer(), 			new SmtpSender(new SmtpClient(emailJob.JobDataMap.GetString(EmailJobKeys.Host), emailJob.JobDataMap.GetInt(EmailJobKeys.Port)) 			{ 				EnableSsl = true, 				Credentials = new NetworkCredential(emailJob.JobDataMap.GetString(EmailJobKeys.UserName), 				emailJob.JobDataMap.GetString(EmailJobKeys.Password)) 			}), 			emailJob.JobDataMap.GetString(EmailJobKeys.UserName), 			emailJob.JobDataMap.GetString(EmailJobKeys.NickName)); 		return fluentEmail; 	});  	IocEngine.Instance.Init(services);  // 实在没办法才弄个静态容器获取service, 监听器里无法通过构造函数 注入 ISchedulerFactory, IFluentEmail, 猜测应该是循环引用了 } 

  基于Asp.Net Core 5.0依赖Quartz.Net框架编写的任务调度web管理平台

 

5、谢谢观看,拜拜