# 引用包 ``` ``` # 触发时间 - 触发原理:当用户在手机上点击了某个按钮,我们需要把延迟的时间记录到Quartz.Net数据表里。 - QuartzNet运作原理:创建一个`IJob`作业,把设置保存到QuartzNet专有的表。当触发的时候,QuartzNet会调用我们定义好的接口,发送极光推送以及把一条通知记录保存到数据库的Noti表。 首先有关配置。 ``` namespace DD.Libs.TasksManager { /// /// 极光配置 /// public class JobSetting : IOptions { public JobSetting Value => this; /// /// 执行场景任务的url /// http://47.103.61.198:5002/api/tasks/cj/ /// public string sceneUrl { get; set; } /// /// 定时任务的url /// http://47.103.61.198:5002/api/tasks/ds/ public string timingUrl { get; set; } /// /// 连接字符串的一部分 /// Port=3306;Database=quartznet;Uid=root;Pwd=pass;SslMode=none /// public string quartz { get; set; } /// /// 连接字符串的一部分 /// 192.168.9.108 /// public string server { get; set; } } } ``` 在`appSetting.json`中配置 ``` "Tasks": { //场景和定时 "sceneUrl": "http://47.103.61.198:5005/api/tasks/noti/", //写字楼版QuartzNet触发发生时调用的接口 "timingUrl": "", //定时地址 "server": "47.103.61.198", "quartz": "Port=3306;Database=ddquartz1;Uid=root;Pwd=TecheDing2019;SslMode=none" }, ``` 接口实现: ``` namespace DD.Warning.WebUI.Controllers { /// /// 场景和定时在这里执行 /// [AllowAnonymous] [Produces("application/json")] [Route("api/tasks")] public class TaiHeRealController : Controller { private readonly IMediator _mediator; //中介者 private readonly ILogger _logger; public TaiHeRealController(IMediator mediator, ILogger logger) { _mediator = mediator; _logger = logger; } /// /// 场景执行 /// /// /// [HttpGet("cj/{extra}")] public async Task cj(string extra) { //rlq_nuode,SceneId,SceneScheduleId string[] tempArr = extra.Split(','); var innerCommand = new AutoTriggerSceneCommand { SceneId = tempArr[1], SceneScheudleId = tempArr[2], ConnKey=tempArr[0] }; _logger.LogWarning($"正在触发场景:{extra}{WarningConstants.LogPlaceholder}", WarningConstants.LogTest); await _mediator.Send(innerCommand); return Ok(); } } } ``` 定义一个`IJob` ``` namespace DD.Libs.TasksManager { public class SceneJob : IJob { private readonly IOptions _settings; public SceneJob(IOptions settings) { _settings = settings; } public async Task Execute(IJobExecutionContext context) { //获取job上下文中传来的额外参数 string extra = context.JobDetail.JobDataMap.GetString("extra"); using(var client = new HttpClient()) { client.Timeout = TimeSpan.FromSeconds(1200); //"http://47.103.61.198:5002/api/tasks/cj/ string url = $"{_settings.Value.sceneUrl }{extra}"; await client.GetAsync(url); } } } } ``` 在`Startup`中注册: ``` #region 场景定时任务,Quartz services.Configure(Configuration.GetSection("Tasks")); services.AddTransient(); NameValueCollection props = new NameValueCollection { { "quartz.threadPool.threadCount","100"}, { "quartz.jobStore.type","Quartz.Impl.AdoJobStore.JobStoreTX, Quartz"}, { "quartz.jobStore.driverDelegateType","Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz"}, { "quartz.jobStore.dataSource","myDS"}, { "quartz.dataSource.myDS.connectionString",$"Server={Configuration["Tasks:server"]};{Configuration["Tasks:quartz"]}"}, //{ "quartz.dataSource.myDS.connectionString",$"server={Configuration["App:redis"]};port=3306;database=quartznet;user=root;password=lcDb_!@34%^_Mantunsci;SslMode=none"}, { "quartz.dataSource.myDS.provider","MySql"}, { "quartz.serializer.type","json"} //{ "quartz.jobStore.useProperties","true"} }; //计划工厂 var schedulerFactory = new StdSchedulerFactory(props); services.AddSingleton(schedulerFactory); //计划工厂 //job工厂 services.AddSingleton();//Job工厂 //帮助类 services.AddSingleton((ctx) => { var tempSchedulerFactory = ctx.GetRequiredService(); var tempJobFactory = ctx.GetRequiredService(); var tempScheduler = tempSchedulerFactory.GetScheduler().Result; tempScheduler.JobFactory = tempJobFactory; var tempJobScheduler = new DDJobScheduler(tempScheduler); return tempJobScheduler; }); #endregion ``` 在请求管道中注册: ``` #region 场景定时任务 var scheduler = serviceProvider.GetService(); scheduler.Init(); #endregion ``` 如何使用呢? ``` public class AddSceneSchedulesCommandHandler : IRequestHandler { private readonly DDJobScheduler _scheduler; public AddSceneSchedulesCommandHandler(DDJobScheduler scheduler) { _scheduler = scheduler; } public async Task Handle(AddSceneSchedulesCommand request, CancellationToken cancellationToken) { await _scheduler.DeleteJob(delJoinName, delGroupName); string cron = JobUtil.GetCronByTime(newSceneSchedule.Hour, newSceneSchedule.Minute, newSceneSchedule.Second, (TimingWeekEnum)newSceneSchedule.Week); await _scheduler.AddSceneJob(joinName, groupName, cron, joinName); return await Task.FromResult(result); } ``` # 调用极光 - 确定别名 - 往数据库的Noti存入一条记录 ``` 对应的领域模型是: /// /// 通知 /// public class Noti : Entity, IAggregateRoot { /// /// 通知标题 /// public string Title { get; private set; } /// /// 通知内容 /// public string Content { get; private set; } /// /// 是否已读 /// public string IsRead { get;private set; } /// /// 通知类型 /// 报警通知的Type=0 /// 延迟断电通知的Type=alert /// public string Type { get; private set; } /// /// 报警通知用的报警级别描述 /// public string Level { get; private set; } /// /// 传递的主键 /// 用来点击某个通知跳转到某个地方 /// public string ExtraId { get; private set; } /// /// 创建方式1 /// /// /// public Noti(string title, string content) { if (string.IsNullOrEmpty(title)) throw new ArgumentNullException("title cannot be null"); if (string.IsNullOrEmpty(content)) throw new ArgumentNullException("content cannot be null"); Title = title; Content = content; CreateTime = DateTime.Now.ToFullTimeStr(); Id = Guid.NewGuid(); LastUpdateTime = DateTime.Now.ToFullTimeStr(); IsLogicDel = CommonConstants.LogicDelNo; } /// /// 创建方式2 /// /// /// /// /// public Noti(string title, string content, string type, string extraId) { if (string.IsNullOrEmpty(title)) throw new ArgumentNullException("title cannot be null"); if (string.IsNullOrEmpty(content)) throw new ArgumentNullException("content cannot be null"); if (string.IsNullOrEmpty(extraId)) throw new ArgumentNullException("extraId cannot be null"); Title = title; Content = content; Type = type; ExtraId = extraId; CreateTime = DateTime.Now.ToFullTimeStr(); Id = Guid.NewGuid(); LastUpdateTime = DateTime.Now.ToFullTimeStr(); IsLogicDel = CommonConstants.LogicDelNo; } /// /// 设置报警级别 /// /// public void SetLevel(string level) { Level = level; } /// /// 标记已读 /// /// public void MarkRead(string regId) { if (string.IsNullOrEmpty(regId)) throw new ArgumentNullException("title cannot be null"); if(string.IsNullOrEmpty(IsRead)) { IsRead = regId; } else { var currentRegIds = regId.Split(',').ToList(); currentRegIds.Add(regId); IsRead = string.Join(',', currentRegIds); } } } //对应的仓储 private readonly INotiRepository _notiRepo; public SomeRequestHandler(INotiRepository notiRepo) { _notiRepo = notiRepo; } //大致用法 var newNoti = new Noti("title","content", "alert", string.Empty); _notiRepo.Add(newNoti); await _notiRepo.UnitOfWork.SaveChangesAsync(cancellationToken); ``` - 极光推送 ``` var request = new JiGuanPushRequest { platform = "all", //audience = "all",//针对所有 audience = new Audience { alias = tempAlias }, notification = new Notification { alert = $"{locationDesc},{kgDesc},{warningDesc}", android = new Android { extras = new Extras { android_key1 = string.Empty, kaiGuanId = cloudKaiGuan.Id.ToString(), connKey = cloudKaiGuan.ConnKey, startTime = startEndTime, warningType = ((short)type).ToString(), projectId = _appOptions.Value.projectid, notiType = "0", //通知消息类型 notiId = notis.Id.ToString() } }, ios = new Ios { sound = "sound.caf", badge = "+1", extras = new Extras2 { ios_key1 = string.Empty, kaiGuanId = cloudKaiGuan.Id.ToString(), connKey = cloudKaiGuan.ConnKey, startTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), warningType = ((short)type).ToString(), projectId = _appOptions.Value.projectid, notiType = "0", //通知消息类型 notiId = notis.Id.ToString() } } }, options = new JiGuangs.Options { apns_production = true } }; var response = await _appOptions.Value.jiguang .WithHeader("Content-Type", "application/json") .WithHeader("Authorization", "Basic M2ZhOTE0NTUzNmEwMDFmY2UwYjg3NjU5OjIxYjE0ZGM0OGZkZjRmMDk4NzZiMTg0MQ==") .PostJsonAsync(request); //相关Dto public class JiGuanPushRequest { [JsonProperty("platform")] public string platform { get; set; } //[JsonProperty("audience")] //public string audience { get; set; } [JsonProperty("audience")] public Audience audience { get; set; } [JsonProperty("notification")] public Notification notification { get; set; } [JsonProperty("options")] public Options options { get; set; } } public class Audience { [JsonProperty("alias")] public List alias { get; set; } = new List(); } public class Android { [JsonProperty("extras")] public Extras extras { get; set; } } public class Extras { [JsonProperty("android-key1")] public string android_key1 { get; set; } [JsonProperty("kaiGuanId")] public string kaiGuanId { get; set; } [JsonProperty("warningType")] public string warningType { get; set; } [JsonProperty("startTime")] public string startTime { get; set; } [JsonProperty("connKey")] public string connKey { get; set; } [JsonProperty("notiType")] public string notiType { get; set; } [JsonProperty("projectId")] public string projectId { get; set; } [JsonProperty("notiId")] public string notiId { get; set; } } public class Extras2 { [JsonProperty("ios-key1")] public string ios_key1 { get; set; } [JsonProperty("kaiGuanId")] public string kaiGuanId { get; set; } [JsonProperty("warningType")] public string warningType { get; set; } [JsonProperty("startTime")] public string startTime { get; set; } [JsonProperty("connKey")] public string connKey { get; set; } [JsonProperty("notiType")] public string notiType { get; set; } [JsonProperty("projectId")] public string projectId { get; set; } [JsonProperty("notiId")] public string notiId { get; set; } } public class Ios { [JsonProperty("sound")] public string sound { get; set; } [JsonProperty("badge")] public string badge { get; set; } [JsonProperty("extras")] public Extras2 extras { get; set; } } public class Notification { [JsonProperty("alert")] public string alert { get; set; } [JsonProperty("android")] public Android android { get; set; } [JsonProperty("ios")] public Ios ios { get; set; } } public class Options { [JsonProperty("apns_production")] public bool apns_production { get; set; } } public class TempRegIdsAndAlias { public string RegId { get; set; } public string Alias { get; set; } } ```