zoukankan      html  css  js  c++  java
  • 基于Asp.Net Core 5.0依赖Quartz.Net框架编写的任务调度web管理平台

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

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

     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, "390915549@qq.com"); // 作者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, 猜测应该是循环引用了
    }
    

      

    5、谢谢观看,拜拜

  • 相关阅读:
    [转]WordPress 主题教程 #2:模板文件和模板
    [转]经验分享:微信小程序外包接单常见问题及流程
    [转]为什么软件开发,人多,事少,还会工作量大?
    [转]Reporting Service部署之访问权限
    [转]SQL Server 2008 如何配置报表管理器
    [转]Reporting Services 中的身份验证类型
    [转]Microsoft SQL SERVER 2008 R2 REPORT SERVICE 匿名登录
    [转]EasyUI 日期格式
    chartjs
    [转]分布式中Redis实现Session终结篇
  • 原文地址:https://www.cnblogs.com/GodX/p/14303681.html
Copyright © 2011-2022 走看看