# 引用包
```
```
# 触发时间
- 触发原理:当用户在手机上点击了某个按钮,我们需要把延迟的时间记录到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; }
}
```