|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519 |
-
- # 引用包
- ```
- <PackageReference Include="Flurl" Version="2.8.2" />
- <PackageReference Include="Flurl.Http" Version="2.4.2" />
- ```
-
- # 触发时间
-
- - 触发原理:当用户在手机上点击了某个按钮,我们需要把延迟的时间记录到Quartz.Net数据表里。
- - QuartzNet运作原理:创建一个`IJob`作业,把设置保存到QuartzNet专有的表。当触发的时候,QuartzNet会调用我们定义好的接口,发送极光推送以及把一条通知记录保存到数据库的Noti表。
-
- 首先有关配置。
- ```
- namespace DD.Libs.TasksManager
- {
- /// <summary>
- /// 极光配置
- /// </summary>
- public class JobSetting : IOptions<JobSetting>
- {
- public JobSetting Value => this;
-
- /// <summary>
- /// 执行场景任务的url
- /// http://47.103.61.198:5002/api/tasks/cj/
- /// </summary>
- public string sceneUrl { get; set; }
-
- /// <summary>
- /// 定时任务的url
- /// http://47.103.61.198:5002/api/tasks/ds/
- public string timingUrl { get; set; }
-
- /// <summary>
- /// 连接字符串的一部分
- /// Port=3306;Database=quartznet;Uid=root;Pwd=pass;SslMode=none
- /// </summary>
- public string quartz { get; set; }
-
- /// <summary>
- /// 连接字符串的一部分
- /// 192.168.9.108
- /// </summary>
- 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
- {
- /// <summary>
- /// 场景和定时在这里执行
- /// </summary>
- [AllowAnonymous]
- [Produces("application/json")]
- [Route("api/tasks")]
- public class TaiHeRealController : Controller
- {
-
- private readonly IMediator _mediator; //中介者
- private readonly ILogger<TaiHeRealController> _logger;
-
- public TaiHeRealController(IMediator mediator, ILogger<TaiHeRealController> logger)
- {
- _mediator = mediator;
- _logger = logger;
- }
-
- /// <summary>
- /// 场景执行
- /// </summary>
- /// <param name="extra"></param>
- /// <returns></returns>
- [HttpGet("cj/{extra}")]
- public async Task<IActionResult> 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<JobSetting> _settings;
-
- public SceneJob(IOptions<JobSetting> 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<JobSetting>(Configuration.GetSection("Tasks"));
- services.AddTransient<SceneJob>();
-
-
- 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<ISchedulerFactory>(schedulerFactory); //计划工厂
-
- //job工厂
- services.AddSingleton<IJobFactory, SimpleInjectorJobFactory>();//Job工厂
-
- //帮助类
- services.AddSingleton<DDJobScheduler>((ctx) => {
-
- var tempSchedulerFactory = ctx.GetRequiredService<ISchedulerFactory>();
- var tempJobFactory = ctx.GetRequiredService<IJobFactory>();
-
- var tempScheduler = tempSchedulerFactory.GetScheduler().Result;
- tempScheduler.JobFactory = tempJobFactory;
- var tempJobScheduler = new DDJobScheduler(tempScheduler);
- return tempJobScheduler;
-
- });
- #endregion
- ```
-
- 在请求管道中注册:
- ```
- #region 场景定时任务
- var scheduler = serviceProvider.GetService<DDJobScheduler>();
- scheduler.Init();
- #endregion
- ```
-
- 如何使用呢?
- ```
- public class AddSceneSchedulesCommandHandler : IRequestHandler<AddSceneSchedulesCommand, ResponseWrapperBase>
- {
-
- private readonly DDJobScheduler _scheduler;
-
- public AddSceneSchedulesCommandHandler(DDJobScheduler scheduler)
- {
- _scheduler = scheduler;
- }
- public async Task<ResponseWrapperBase> 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存入一条记录
- ```
- 对应的领域模型是:
-
- /// <summary>
- /// 通知
- /// </summary>
- public class Noti : Entity<Guid>, IAggregateRoot
- {
- /// <summary>
- /// 通知标题
- /// </summary>
- public string Title { get; private set; }
- /// <summary>
- /// 通知内容
- /// </summary>
- public string Content { get; private set; }
- /// <summary>
- /// 是否已读
- /// </summary>
- public string IsRead { get;private set; }
-
- /// <summary>
- /// 通知类型
- /// 报警通知的Type=0
- /// 延迟断电通知的Type=alert
- /// </summary>
- public string Type { get; private set; }
-
- /// <summary>
- /// 报警通知用的报警级别描述
- /// </summary>
- public string Level { get; private set; }
-
- /// <summary>
- /// 传递的主键
- /// 用来点击某个通知跳转到某个地方
- /// </summary>
- public string ExtraId { get; private set; }
-
- /// <summary>
- /// 创建方式1
- /// </summary>
- /// <param name="title"></param>
- /// <param name="content"></param>
- 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;
- }
-
- /// <summary>
- /// 创建方式2
- /// </summary>
- /// <param name="title"></param>
- /// <param name="content"></param>
- /// <param name="type"></param>
- /// <param name="extraId"></param>
- 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;
- }
-
- /// <summary>
- /// 设置报警级别
- /// </summary>
- /// <param name="level"></param>
- public void SetLevel(string level)
- {
- Level = level;
- }
-
- /// <summary>
- /// 标记已读
- /// </summary>
- /// <param name="regId"></param>
- 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<string> alias { get; set; } = new List<string>();
- }
-
- 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; }
- }
- ```
|