This commit is contained in:
2026-02-06 18:34:35 +08:00
commit f7f4c94c00
3285 changed files with 563208 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace iMES.Core.Quartz
{
public static class HttpManager
{
public static async Task<string> SendAsync(this IHttpClientFactory httpClientFactory,
HttpMethod method,
string url,
string postData=null,
int timeOut=180,
Dictionary<string, string> headers = null)
{
var client = httpClientFactory.CreateClient();
var content = new StringContent(postData??"");
var request = new HttpRequestMessage(method, url)
{
Content = content
};
headers ??= new Dictionary<string, string>();
headers.TryAdd(QuartzAuthorization.Key, QuartzAuthorization.AccessKey);
if (headers != null)
{
foreach (var header in headers)
{
request.Headers.Add(header.Key, header.Value);
}
}
try
{
client.Timeout = TimeSpan.FromSeconds(timeOut);
HttpResponseMessage httpResponseMessage = await client.SendAsync(request);
var result = await httpResponseMessage.Content
.ReadAsStringAsync();
return result;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
QuartzFileHelper.Error($"http请求异常url:{url},{ex.Message+ex.StackTrace}");
return ex.Message;
}
}
}
}

View File

@@ -0,0 +1,134 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Quartz;
using Quartz.Impl;
using Quartz.Impl.Triggers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using iMES.Core.Configuration;
using iMES.Core.EFDbContext;
using iMES.Core.Utilities;
using iMES.Entity.DomainModels;
namespace iMES.Core.Quartz
{
public class HttpResultfulJob : IJob
{
readonly IHttpClientFactory _httpClientFactory;
readonly IServiceProvider _serviceProvider;
/// <summary>
/// 2020.05.31增加构造方法
/// </summary>
/// <param name="serviceProvider"></param>
/// <param name="httpClientFactory"></param>
public HttpResultfulJob(IServiceProvider serviceProvider, IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
_serviceProvider = serviceProvider;
}
public async Task Execute(IJobExecutionContext context)
{
DateTime dateTime = DateTime.Now;
Sys_QuartzOptions taskOptions = context.GetTaskOptions();
string httpMessage = "";
AbstractTrigger trigger = (context as JobExecutionContextImpl).Trigger as AbstractTrigger;
if (taskOptions == null)
{
Console.WriteLine($"未获取到作业");
return;
}
if (string.IsNullOrEmpty(taskOptions.ApiUrl) || taskOptions.ApiUrl == "/")
{
Console.WriteLine($"未配置作业:{taskOptions.TaskName}的url地址");
QuartzFileHelper.Error($"未配置作业:{taskOptions.TaskName}的url地址");
return;
}
string exceptionMsg = null;
try
{
using (var dbContext = new SysDbContext())
{
var _taskOptions = dbContext.Set<Sys_QuartzOptions>().AsTracking()
.Where(x => x.Id == taskOptions.Id).FirstOrDefault();
if (_taskOptions != null)
{
dbContext.Update(_taskOptions);
var entry = dbContext.Entry(_taskOptions);
entry.State = EntityState.Unchanged;
entry.Property("LastRunTime").IsModified = true;
_taskOptions.LastRunTime = DateTime.Now;
dbContext.SaveChanges();
}
}
Dictionary<string, string> header = new Dictionary<string, string>();
if (!string.IsNullOrEmpty(taskOptions.AuthKey)
&& !string.IsNullOrEmpty(taskOptions.AuthValue))
{
header.Add(taskOptions.AuthKey.Trim(), taskOptions.AuthValue.Trim());
}
httpMessage = await _httpClientFactory.SendAsync(
taskOptions.Method?.ToLower() == "get" ? HttpMethod.Get : HttpMethod.Post,
taskOptions.ApiUrl,
taskOptions.PostData,
taskOptions.TimeOut ?? 180,
header); ;
}
catch (Exception ex)
{
exceptionMsg = ex.Message + ex.StackTrace;
}
finally
{
try
{
var log = new Sys_QuartzLog
{
LogId = Guid.NewGuid(),
TaskName = taskOptions.TaskName,
Id = taskOptions.Id,
CreateDate = dateTime,
ElapsedTime = Convert.ToInt32((DateTime.Now - dateTime).TotalSeconds),
ResponseContent = httpMessage,
ErrorMsg = exceptionMsg,
StratDate = dateTime,
Result = exceptionMsg == null ? 1 : 0,
EndDate = DateTime.Now
};
using (var dbContext = new SysDbContext())
{
dbContext.Set<Sys_QuartzLog>().Add(log);
dbContext.SaveChanges();
}
}
catch (Exception ex)
{
Console.WriteLine($"日志写入异常:{taskOptions.TaskName},{ex.Message}");
QuartzFileHelper.Error($"日志写入异常:{typeof(HttpResultfulJob).Name},{taskOptions.TaskName},{ex.Message}");
}
}
Console.WriteLine(trigger.FullName + " " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:sss") + " " + httpMessage);
return;
}
}
public class TaskOptions
{
public string TaskName { get; set; }
public string GroupName { get; set; }
public string Interval { get; set; }
public string ApiUrl { get; set; }
public string AuthKey { get; set; }
public string AuthValue { get; set; }
public string Describe { get; set; }
public string RequestType { get; set; }
public DateTime? LastRunTime { get; set; }
public int Status { get; set; }
}
}

View File

@@ -0,0 +1,28 @@
using Quartz;
using Quartz.Spi;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace iMES.Core.Quartz
{
public class IOCJobFactory: IJobFactory
{
private readonly IServiceProvider _serviceProvider;
public IOCJobFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
return _serviceProvider.GetService(bundle.JobDetail.JobType) as IJob;
}
public void ReturnJob(IJob job)
{
(job as IDisposable)?.Dispose();
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace iMES.Core.Quartz
{
public enum JobAction
{
= 1,
= 2,
= 3,
= 4,
,
,
}
}

View File

@@ -0,0 +1,69 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using iMES.Core.Configuration;
using iMES.Core.Extensions;
namespace iMES.Core.Quartz
{
public static class QuartzAuthorization
{
private static string _quartzAccessKey;
public static string Key = "QuartzAccessKey";
public static string AccessKey
{
get
{
if (string.IsNullOrEmpty(_quartzAccessKey))
{
_quartzAccessKey = GetAccessKey();
}
return _quartzAccessKey;
}
}
public static string GetAccessKey()
{
if (string.IsNullOrEmpty(_quartzAccessKey))
{
_quartzAccessKey = AppSetting.GetSettingString(Key);
}
if (string.IsNullOrEmpty(_quartzAccessKey))
{
_quartzAccessKey = Guid.NewGuid().ToString();
}
using (MD5 md5 = MD5.Create())
{
string md5str = _quartzAccessKey;
byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(AppSetting.Secret.User));
for (int i = 0; i < s.Length; i++)
{
string btos = s[i].ToString("X2");
md5str += btos;
}
return md5str;
}
}
public static AuthorizationFilterContext Validation(AuthorizationFilterContext context)
{
bool result = context.HttpContext.Request.Headers.TryGetValue(Key, out StringValues value);
if (!result || AccessKey != value)
{
context.Result = new ContentResult()
{
Content = new { message = "key不匹配", status = false, code = 401 }.Serialize(),
ContentType = "application/json",
StatusCode = 401
};
return context;
}
return context;
}
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Text;
using iMES.Core.Configuration;
using iMES.Core.Extensions;
using iMES.Core.Utilities;
namespace iMES.Core.Quartz
{
public static class QuartzFileHelper
{
public static void OK(string message)
{
Write(message, "log");
}
public static void Error(string message)
{
Write(message, "error");
}
private static void Write(string message,string folder)
{
try
{
string fileName = DateTime.Now.ToString("yyyy-MM-dd");
string path = $"{AppSetting.CurrentPath}\\quartz\\{folder}\\".ReplacePath();
FileHelper.WriteFile(path, $"{fileName}.txt", message, true);
}
catch (Exception ex)
{
Console.WriteLine($"文件写入异常{message},{ex.Message + ex.StackTrace}");
}
}
}
}

View File

@@ -0,0 +1,317 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Quartz;
using Quartz.Impl;
using Quartz.Impl.Matchers;
using Quartz.Impl.Triggers;
using Quartz.Spi;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using iMES.Core.DBManager;
using iMES.Core.EFDbContext;
using iMES.Core.Extensions;
using iMES.Core.Utilities;
using iMES.Entity.DomainModels;
namespace iMES.Core.Quartz
{
public static class QuartzNETExtension
{
private static List<Sys_QuartzOptions> _taskList = new List<Sys_QuartzOptions>();
/// <summary>
/// 初始化作业
/// </summary>
/// <param name="applicationBuilder"></param>
/// <param name="env"></param>
/// <returns></returns>
public static IApplicationBuilder UseQuartz(this IApplicationBuilder applicationBuilder, IWebHostEnvironment env)
{
IServiceProvider services = applicationBuilder.ApplicationServices;
ISchedulerFactory _schedulerFactory = services.GetService<ISchedulerFactory>();
try
{
_taskList = services.GetService<SysDbContext>().Set<Sys_QuartzOptions>().Where(x=>x.Status==0).ToList();
for (int i = 0; i < 1; i++)
{
_taskList.Add(new Sys_QuartzOptions()
{
Id = Guid.NewGuid(),
GroupName = $"group{i}",
TaskName = $"task{i}",
CronExpression = "0 0 0 1 * ?",
Status = 0
});
}
_taskList.ForEach(options =>
{
options.AddJob(_schedulerFactory, jobFactory: services.GetService<IJobFactory>()).GetAwaiter().GetResult();
});
}
catch (Exception ex)
{
Console.WriteLine($"作业启动异常:{ex.Message + ex.StackTrace}");
}
return applicationBuilder;
}
/// <summary>
/// 添加作业
/// </summary>
/// <param name="taskOptions"></param>
/// <param name="schedulerFactory"></param>
/// <param name="init">是否初始化,否=需要重新生成配置文件,是=不重新生成配置文件</param>
/// <returns></returns>
public static async Task<object> AddJob(this Sys_QuartzOptions taskOptions, ISchedulerFactory schedulerFactory, IJobFactory jobFactory = null)
{
string msg = null;
try
{
if (!_taskList.Exists(x => x.Id == taskOptions.Id))
{
_taskList.Add(taskOptions);
}
else
{
_taskList = _taskList.Where(x => x.Id != taskOptions.Id).ToList();
_taskList.Add(taskOptions);
}
taskOptions.GroupName = "group";
(bool, string) validExpression = taskOptions.CronExpression.IsValidExpression();
if (!validExpression.Item1)
{
msg = $"添加作业失败,作业:{taskOptions.TaskName},表达式不正确:{ taskOptions.CronExpression}";
Console.WriteLine(msg);
QuartzFileHelper.Error(msg);
return new { status = false, msg = validExpression.Item2 };
}
IJobDetail job = JobBuilder.Create<HttpResultfulJob>()
.WithIdentity(taskOptions.Id.ToString(), "group").Build();
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity(taskOptions.Id.ToString(), "group")
// .st()
.WithDescription(taskOptions.Describe)
.WithCronSchedule(taskOptions.CronExpression)
.Build();
IScheduler scheduler = await schedulerFactory.GetScheduler();
if (jobFactory == null)
{
jobFactory = HttpContext.Current.RequestServices.GetService<IJobFactory>();
}
if (jobFactory != null)
{
scheduler.JobFactory = jobFactory;
}
await scheduler.ScheduleJob(job, trigger);
await scheduler.Start();
msg = $"作业启动:{taskOptions.TaskName}";
Console.WriteLine(msg);
QuartzFileHelper.Error(msg);
//if (taskOptions.Status == (int)TriggerState.Normal)
//{
// await scheduler.Start();
// msg = $"作业启动:{taskOptions.TaskName}";
// Console.WriteLine(msg);
// QuartzFileHelper.Error(msg);
//}
//else
//{
// await scheduler.PauseJob(job.Key);
//}
}
catch (Exception ex)
{
msg = $"作业启动异常:{taskOptions.TaskName},{ex.Message}";
Console.WriteLine(msg);
QuartzFileHelper.Error(msg);
return new { status = false, msg = ex.Message };
}
return new { status = true };
}
/// <summary>
/// 移除作业
/// </summary>
/// <param name="schedulerFactory"></param>
/// <param name="taskName"></param>
/// <param name="groupName"></param>
/// <returns></returns>
public static Task<object> Remove(this ISchedulerFactory schedulerFactory, Sys_QuartzOptions taskOptions)
{
return schedulerFactory.TriggerAction(JobAction., taskOptions);
}
/// <summary>
/// 更新作业
/// </summary>
/// <param name="schedulerFactory"></param>
/// <param name="taskOptions"></param>
/// <returns></returns>
public static Task<object> Update(this ISchedulerFactory schedulerFactory, Sys_QuartzOptions taskOptions)
{
return schedulerFactory.TriggerAction(JobAction., taskOptions);
}
/// <summary>
/// 暂停作业
/// </summary>
/// <param name="schedulerFactory"></param>
/// <param name="taskOptions"></param>
/// <returns></returns>
public static Task<object> Pause(this ISchedulerFactory schedulerFactory, Sys_QuartzOptions taskOptions)
{
return schedulerFactory.TriggerAction(JobAction., taskOptions);
}
/// <summary>
/// 启动作业
/// </summary>
/// <param name="schedulerFactory"></param>
/// <param name="taskOptions"></param>
/// <returns></returns>
public static Task<object> Start(this ISchedulerFactory schedulerFactory, Sys_QuartzOptions taskOptions)
{
return taskOptions.AddJob(schedulerFactory);
// return schedulerFactory.TriggerAction(JobAction.开启, taskOptions);
}
/// <summary>
/// 立即执行一次作业
/// </summary>
/// <param name="schedulerFactory"></param>
/// <param name="taskOptions"></param>
/// <returns></returns>
public static Task<object> Run(this ISchedulerFactory schedulerFactory, Sys_QuartzOptions taskOptions)
{
return schedulerFactory.TriggerAction(JobAction., taskOptions);
}
/// <summary>
/// 触发新增、删除、修改、暂停、启用、立即执行事件
/// </summary>
/// <param name="schedulerFactory"></param>
/// <param name="taskName"></param>
/// <param name="groupName"></param>
/// <param name="action"></param>
/// <param name="taskOptions"></param>
/// <returns></returns>
public static async Task<object> TriggerAction(
this ISchedulerFactory schedulerFactory,
JobAction action,
Sys_QuartzOptions taskOptions = null)
{
string errorMsg = "";
try
{
string groupName = "group";
string taskName = taskOptions.Id.ToString();
IScheduler scheduler = await schedulerFactory.GetScheduler();
List<JobKey> jobKeys = scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals(groupName)).Result.ToList();
if (jobKeys == null || jobKeys.Count() == 0)
{
errorMsg = $"未找到分组[{groupName}]";
return new { status = false, msg = errorMsg };
}
JobKey jobKey = jobKeys.Where(s => scheduler.GetTriggersOfJob(s).Result
.Any(x => (x as CronTriggerImpl).Name == taskName))
.FirstOrDefault();
if (jobKey == null)
{
errorMsg = $"未找到触发器[{taskName}]";
return new { status = false, msg = errorMsg };
}
var triggers = await scheduler.GetTriggersOfJob(jobKey);
ITrigger trigger = triggers?.Where(x => (x as CronTriggerImpl).Name == taskName).FirstOrDefault();
if (trigger == null)
{
errorMsg = $"未找到触发器[{taskName}]";
return new { status = false, msg = errorMsg };
}
object result = null;
switch (action)
{
case JobAction.:
case JobAction.:
case JobAction.:
await scheduler.PauseTrigger(trigger.Key);
await scheduler.UnscheduleJob(trigger.Key);// 移除触发器
await scheduler.DeleteJob(trigger.JobKey);
if (action==JobAction.)
{
taskOptions.Status = (int)JobAction.;
}
break;
case JobAction.:
await scheduler.ResumeTrigger(trigger.Key);
await scheduler.TriggerJob(jobKey);
break;
}
return result ?? new { status = true, msg = $"作业{action.ToString()}成功" };
}
catch (Exception ex)
{
errorMsg = ex.Message;
return new { status = false, msg = ex.Message };
}
}
/// <summary>
///
/// </summary>
/// <param name="context"></param>通过作业上下文获取作业对应的配置参数
/// <returns></returns>
public static Sys_QuartzOptions GetTaskOptions(this IJobExecutionContext context)
{
AbstractTrigger trigger = (context as JobExecutionContextImpl).Trigger as AbstractTrigger;
Sys_QuartzOptions taskOptions = _taskList.Where(x => x.Id.ToString() == trigger.Name).FirstOrDefault();
return taskOptions ?? _taskList.Where(x => x.Id.ToString() == trigger.JobName).FirstOrDefault();
}
/// <summary>
/// 作业是否存在
/// </summary>
/// <param name="taskOptions"></param>
/// <param name="init">初始化的不需要判断</param>
/// <returns></returns>
public static (bool, object) Exists(this Sys_QuartzOptions taskOptions, bool init)
{
if (!init && _taskList.Any(x => x.TaskName == taskOptions.TaskName && x.GroupName == taskOptions.GroupName))
{
return (false,
new
{
status = false,
msg = $"作业:{taskOptions.TaskName},分组:{taskOptions.GroupName}已经存在"
});
}
return (true, null);
}
public static (bool, string) IsValidExpression(this string cronExpression)
{
try
{
CronTriggerImpl trigger = new CronTriggerImpl();
trigger.CronExpressionString = cronExpression;
DateTimeOffset? date = trigger.ComputeFirstFireTimeUtc(null);
return (date != null, date == null ? $"请确认表达式{cronExpression}是否正确!" : "");
}
catch (Exception e)
{
return (false, $"请确认表达式{cronExpression}是否正确!{e.Message}");
}
}
}
}