zoukankan      html  css  js  c++  java
  • 定时器_使用C#开发windows服务定时发消息到钉钉群_群组简单消息

    前言:本提醒服务,是由C#语言开发的,主要由windows服务项目和winform项目组成,运行服务可实现功能:向钉钉自定义机器人群组里,定时,定次,推送多个自定义消息内容,并实现主要功能的日志记录。  可以说功能强大!!!

    备注: 本文主要2部分:1-关键代码,2-安装步骤。   

    A-关键代码:

    1-服务:

    public partial class MyTipsService : ServiceBase
        {
            public MyTipsService()
            {
                InitializeComponent();
            }
    
            protected override void OnStart(string[] args)
            {
                //服务启动
                List<TimeCycle> timeCycleList = new List<TimeCycle> {
                    new TimeCycle {
                        ID=1,
                        Action =this.SendTipsToDingding,
                        BeginTime="09:05:00",
                        EndTime="09:15:00",
                        MaxActionTimes=2,
                        ActionSeconds=120
                    },
                    new TimeCycle {
                        ID=2,
                        Action =this.SendTipsToDingding,
                        BeginTime="17:50:00",
                        EndTime="18:05:00",
                        MaxActionTimes=2,
                        ActionSeconds=120
                    },
                    new TimeCycle {
                        ID=3,
                        Action =this.MyProjectBugTips,
                        BeginTime="09:10:00",
                        EndTime="09:15:00",
                        MaxActionTimes=1,
                        ActionSeconds=1
                    },
                };
    
                MyLog.WriteLog("服务启动");
                MyServiceHelp myServiceHelp = new MyServiceHelp(timeCycleList);
                myServiceHelp.Start();
    
            }
    
            protected override void OnStop()
            {
                //服务终止
                MyLog.WriteLog("服务终止");
            }
    
    
            /// <summary>
            /// 测试方法
            /// </summary>
            public void Test()
            {
                MyProjectBugTips();
            }
    
    
            #region 获取提醒消息
    
            /// <summary>
            /// 每天上下班提醒
            /// </summary>
            private void SendTipsToDingding()
            {
                MyLog.WatchAction(() =>
                {
                    StringBuilder strBuilder = new StringBuilder();
                    DateTime now = DateTime.Now;
                    if (now.Hour < 12)
                    {
                        strBuilder.Append("现在时间是:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "
    ");
                        strBuilder.Append("上班记得打卡!打卡迟到时间不能大于60分钟,多1分钟扣10块!
    ");
                        strBuilder.Append("上班记得佩戴胸牌!被抓住一次扣30块钱!
    ");
                    }
                    else
                    {
                        strBuilder.Append("现在时间是:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "
    ");
                        strBuilder.Append("下班记得打卡!
    ");
                    }
    
    
                    string shangbanTipMessage = strBuilder.ToString();
    
                    if (!string.IsNullOrEmpty(shangbanTipMessage))
                    {
                        DingDingHelp dingdingInstance = new DingDingHelp(ConfigHelper.GetAppSettingValue("dingdingGroupUrl"));
                        string result = dingdingInstance.SendMesasge(shangbanTipMessage, "接收人手机号");
    
                        MyLog.WriteLog("发送打卡提醒消息结果:" + result);
                    }
                });
            }
    
            /// <summary>
            /// 我的项目BUG的提醒
            /// </summary>
            private void MyProjectBugTips()
            {
                MyLog.WatchAction(() =>
                {
                    DateTime now = DateTime.Now;
    
                    List<string> bugWhereList = new List<string>(4);
                    bugWhereList.Add(string.Format(@"{0}!='{1}'", Sys_commonlog._LOGTYPE_, "HttpException"));
                    bugWhereList.Add(string.Format(@"{0}>='{1}'", Sys_commonlog._CREATETIME_, now.AddDays(-1)));
                    bugWhereList.Add(string.Format(@"{0}<='{1}'", Sys_commonlog._CREATETIME_, now));
    
    
                    //A-获取所有人的异常监控配置
                    NameValueCollection userNameValueColl = ConfigHelper.GetSectionNameValueCollection("bugUser");
                    Dictionary<string, List<string>> userKeyWordListDic = new Dictionary<string, List<string>>(userNameValueColl.Count);
                    List<string> userNameList = new List<string>(userNameValueColl.Count);
                    List<string> userPhoneList = new List<string>(userNameValueColl.Count);
    
                    List<string> allKeyWordWhereList = new List<string>(0);
                    string[] userArray = null;
    
                    foreach (string userKeyAt in userNameValueColl)
                    {
                        if (!string.IsNullOrEmpty(userKeyAt))
                        {
                            userArray = userKeyAt.Split(',');
                            if (userArray.Length > 1)
                            {
                                string userName = userArray[0];
                                userNameList.Add(userName);
                                userPhoneList.Add(userArray[1]);
    
                                userKeyWordListDic.Add(userName, userNameValueColl[userKeyAt].Split(',').ToList());
    
                                if (userKeyWordListDic[userName].Count > 0)
                                {
                                    foreach (string keyWord in userKeyWordListDic[userName])
                                    {
                                        allKeyWordWhereList.Add(string.Format(@"{0} LIKE '%{1}%'", Sys_commonlog._URL_, keyWord));
                                    }
                                }
    
                            }
                        }
                    }
                    userNameValueColl = null;
    
    
                    string whereSql = string.Format(@"{0} AND ({1})", string.Join(" AND ", bugWhereList), string.Join(" OR ", allKeyWordWhereList));
                    allKeyWordWhereList.Clear();
                    allKeyWordWhereList = null;
                    bugWhereList.Clear();
                    bugWhereList = null;
    
                    //B-获取所有站点
                    string[] websiteNameArray = ConfigHelper.GetAppSettingValue("websiteName").Split(',');
    
    
                    //C-收集每个人每个站的BUG汇总信息
    
                    Dictionary<string, List<Sys_commonlog>> websiteDataListDic = new Dictionary<string, List<Sys_commonlog>>(websiteNameArray.Length);
    
                    Sys_commonlogDAL instance = new Sys_commonlogDAL();
                    foreach (string webSiteName in websiteNameArray)
                    {
                        websiteDataListDic.Add(webSiteName, instance.Select(whereSql, Sys_commonlog._ID_ + " DESC", Conn.GetConnectionString("Constr_" + webSiteName)));
                    }
    
                    List<UserExectionHelp> userExectionHelpList = new List<UserExectionHelp>(userNameList.Count);
                    List<Sys_commonlog> userWebsiteCommonLogList = null;
                    List<WebSiteExectionHelp> webSiteExectionHelpList = null;
                    WebSiteExectionHelp webSiteExection = null;
                    int userBugTotalCount = 0;
                    List<string> userKeyWordList = null;
                    for (var i = 0; i < userNameList.Count; i++)
                    {
                        userKeyWordList = userKeyWordListDic[userNameList[i]];
                        webSiteExectionHelpList = new List<WebSiteExectionHelp>(websiteNameArray.Length);
                        foreach (var websiteDicItem in websiteDataListDic)
                        {
                            foreach (var userKeyWord in userKeyWordList)
                            {
                                userWebsiteCommonLogList = websiteDicItem.Value.FindAll(item => item.Url.Split('?')[0].Contains(userKeyWord));
                                if (userWebsiteCommonLogList.Count > 0)
                                {
                                    break;
                                }
                            }
                            if (userWebsiteCommonLogList != null && userWebsiteCommonLogList.Count > 0)
                            {
                                userBugTotalCount += userWebsiteCommonLogList.Count;
                                webSiteExection = new WebSiteExectionHelp { WebsiteName = websiteDicItem.Key, TotalCount = userWebsiteCommonLogList.Count, ExectionHelpList = userWebsiteCommonLogList };
                                webSiteExectionHelpList.Add(webSiteExection);
                            }
                        }
    
                        if (webSiteExectionHelpList.Count > 0)
                        {
                            userExectionHelpList.Add(new UserExectionHelp { UserName = userNameList[i], UserPhone = userPhoneList[i], TotalCount = userBugTotalCount, WebSiteExectionHelpList = webSiteExectionHelpList });
                        }
    
                        //重置bug总数
                        userBugTotalCount = 0;
    
                    }
    
                    //D-循环输出信息
                    DingDingHelp dingdingInstance = new DingDingHelp(ConfigHelper.GetAppSettingValue("dingdingGroupUrl"));
                    Sys_commonlog execItem = null;
                    StringBuilder strBuilder = new StringBuilder();
                    //等待发送的消息数量
                    int toBeSendMessageCount = 0;
                    userExectionHelpList.ForEach(item =>
                    {
                        strBuilder.AppendFormat("网站异常_{0}_{1}_BUG总数:{2}:
    ", item.UserName, now.ToShortDateString(), item.TotalCount);
                        MyLog.WriteLog(string.Format("网站异常_{0}_{1}_BUG总数:{2}:", item.UserName, now.ToShortDateString(), item.TotalCount));
    
                        item.WebSiteExectionHelpList.ForEach(webItem =>
                        {
                            for (var i = 0; i < webItem.ExectionHelpList.Count; i++)
                            {
                                execItem = webItem.ExectionHelpList[i];
                                strBuilder.AppendFormat("【{0}-BUG-{1}】:
    ", webItem.WebsiteName, (i + 1));
                                strBuilder.AppendFormat("ID:{0}
    LogType:{1}
    CreateTime:{2}
    LogContent:{3}
    Url:{4}
    ", execItem.ID, execItem.LogType, execItem.CreateTime, execItem.LogContent, execItem.Url);
                                toBeSendMessageCount++;
                                //超出50条自动发送
                                if (toBeSendMessageCount >= 50)
                                {
                                    dingdingInstance.SendMesasge(strBuilder.ToString(), item.UserPhone);
                                    toBeSendMessageCount = 0;
                                    strBuilder.Clear();
                                }
                            }
                        });
                        //发送剩余未发送消息数量
                        if (toBeSendMessageCount > 0)
                        {
                            dingdingInstance.SendMesasge(strBuilder.ToString(), item.UserPhone);
                            strBuilder.Clear();
                        }
                        toBeSendMessageCount = 0;
                    });
                    strBuilder = null;
    
                    userNameList.Clear();
                    userNameList = null;
                    userPhoneList.Clear();
                    userPhoneList = null;
    
                    userExectionHelpList.Clear();
                    userExectionHelpList = null;
                    if (userWebsiteCommonLogList != null)
                    {
                        userWebsiteCommonLogList.Clear();
                        userWebsiteCommonLogList = null;
                    }
                    websiteDataListDic.Clear();
                    websiteDataListDic = null;
                    if (webSiteExectionHelpList != null)
                    {
                        webSiteExectionHelpList.Clear();
                        webSiteExection = null;
                    }
                });
            }
    
            #endregion
    
        }

    原来服务帮助类中遇到了很多问题,如:如何统计多个任务中,每个任务的已执行次数问题?  如何让多个任务准时执行?   如何让多个任务中,每个任务按照自己的任务间隔执行?

    针对这些问题,就设计了一个TimeCycel类(包含一个任务的ID,任务内容,任务的开始时间,任务时间间隔,任务已执行次数,任务最大执行次数)。

    重点:服务运行后会形成一个单例模式,计时器,及服务帮助类的所有属性的初始化值,均会存在该单例中,因此我们可以将每个任务的信息记录在每个任务的实例中去,这样更合理;另外在任务执行时,新增了多线程的使用来处理任务的准时和执行次数问题。

    原本走过一些弯路:原本TimeCycel类中没有任务已执行次数属性,我是通过一个方法计算的:当前时间-任务开始时间/任务执行间隔,计算的,但是这个方式计算存在时延问题以及任务的执行快慢,无法保证执行次数和执行间隔的准确性,使用每个任务的实例单独统计快捷方便,保证了已执行次数的准确性。

    public class MyServiceHelp
        {
            public MyServiceHelp(List<TimeCycle> timeCycleList)
            {
                this.TimeCycleList = timeCycleList;
                this.Timer = new Timer();
            }
    
            /// <summary>
            /// 服务专属计时器
            /// </summary>
            private System.Timers.Timer Timer;
    
            /// <summary>
            /// 默认计时器时间间隔1秒(提高计时器开始时间准确度)
            /// </summary>
            private double DefaultTimerInterval = 1 * 1000;
    
            /// <summary>
            /// 设置多个循环周期
            /// </summary>
            public List<TimeCycle> TimeCycleList { get; set; }
    
    
            /// <summary>
            /// 更新一个计时器的计时周期
            /// </summary>
            /// <param name="newTimerInterval">新的计时周期</param>
            /// <param name="isFirstStart">是否是首次更新计时器周期</param>
            public void UpdateTimeInterval(double newTimerInterval, bool isFirstStart = false)
            {
                if (this.Timer != null && newTimerInterval > 0)
                {
                    this.Timer.Stop();
                    if (this.Timer.Interval != newTimerInterval)
                    {
                        this.Timer.Interval = newTimerInterval;
                    }
                    if (isFirstStart)
                    {
                        this.Timer.Elapsed += new System.Timers.ElapsedEventHandler(this.ServiceAction);
                    }
                    this.Timer.AutoReset = true;
                    this.Timer.Start();
                }
            }
    
            /// <summary>
            /// 内部辅助方法
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void ServiceAction(object sender, ElapsedEventArgs e)
            {
                List<TimeCycle> currentTimeCycleList = new List<TimeCycle>(0);
    
                DateTime now = DateTime.Now;
                DateTime cycleBeginTime;
                DateTime cycleEndTime;
                foreach (TimeCycle timeCycle in this.TimeCycleList)
                {
                    cycleBeginTime = Convert.ToDateTime(timeCycle.BeginTime);
                    cycleBeginTime = now.Date.AddHours(cycleBeginTime.Hour).AddMinutes(cycleBeginTime.Minute).AddSeconds(cycleBeginTime.Second);
                    cycleEndTime = Convert.ToDateTime(timeCycle.EndTime);
                    cycleEndTime = now.Date.AddHours(cycleEndTime.Hour).AddMinutes(cycleEndTime.Minute).AddSeconds(cycleEndTime.Second);
                    if (cycleEndTime < cycleBeginTime)
                    {
                        cycleEndTime = cycleEndTime.AddDays(1);
                    }
    
                    if (now >= cycleBeginTime && now <= cycleEndTime)
                    {
                        if (timeCycle.ActionExecutionTimes < timeCycle.MaxActionTimes)
                        {
                            TimeSpan timeSpan = now - cycleBeginTime;
                            bool isCanAction = (int)timeSpan.TotalSeconds % timeCycle.ActionSeconds == 0 ? true : false;
                            if (isCanAction)
                            {
                                timeCycle.ActionExecutionTimes++;
                                currentTimeCycleList.Add(timeCycle);
                            }
                        }
                    }
                    else
                    {
                        //不在计时周期内,已执行次数清零
                        timeCycle.ActionExecutionTimes = 0;
                    }
                }
                //找到当前循环周期后,执行周期内动作
                if (currentTimeCycleList.Count > 0)
                {
                    currentTimeCycleList.ForEach(item =>
                    {
                        //使用多线程执行任务,让代码快速执行
                        Task.Run(item.Action);
                    });
                }
            }
    
            public void Start()
            {
                //设置首次计时器周期(首次动作执行,是在计时器启动后在设置的时间间隔后做出的动作)
                this.UpdateTimeInterval(this.DefaultTimerInterval, true);
    
            }
    
        }
    
        /// <summary>
        /// 计时周期类
        /// </summary>
        public class TimeCycle
        {
            /// <summary>
            /// 唯一标识
            /// </summary>
            public int ID { get; set; }
            /// <summary>
            /// 开始时间(误差1秒=取决于计时器默认时间间隔)
            /// </summary>
            public string BeginTime { get; set; }
            /// <summary>
            /// 结束时间
            /// </summary>
            public string EndTime { get; set; }
            /// <summary>
            /// 最大执行次数
            /// </summary>
            public int MaxActionTimes { get; set; }
            /// <summary>
            /// 计时周期内执行的动作(动作会在到达开始时间后的)
            /// </summary>
            public Action Action { get; set; }
            /// <summary>
            /// 动作执行时间间隔(秒)
            /// </summary>
            public int ActionSeconds { get; set; }
            /// <summary>
            /// 方法执行次数
            /// </summary>
            internal int ActionExecutionTimes { get; set; }
        }

    2-服务管理windowform代码:

    public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
                this.textServicePath.Text = ConfigHelper.GetAppSettingValue("serviceExeUrl");
            }
    
            private static string serviceName = "MyTips";
    
    
            private void btnStartService_Click(object sender, EventArgs e)
            {
                this.InstallService();
            }
    
            private void btnEndService_Click(object sender, EventArgs e)
            {
                this.UninstallService();
            }
    
            private void btnTestService_Click(object sender, EventArgs e)
            {
                new MyTipsService().Test();
            }
    
    
            //判断服务是否存在
            private bool IsServiceExisted()
            {
                ServiceController[] services = ServiceController.GetServices();
                foreach (ServiceController sc in services)
                {
                    if (sc.ServiceName.ToLower() == serviceName.ToLower())
                    {
                        return true;
                    }
                }
                return false;
            }
    
            //安装服务
            private void InstallService()
            {
                if (IsServiceExisted() == false)
                {
                    string[] args = new string[] { this.textServicePath.Text };
                    ManagedInstallerClass.InstallHelper(args);
                    MessageBox.Show("安装成功!");
    
                    using (ServiceController control = new ServiceController(serviceName))
                    {
                        if (control.Status == ServiceControllerStatus.Stopped)
                        {
                            control.Start();
                        }
                    }
                }
                else
                {
                    MessageBox.Show("已安装!");
                }
            }
    
            //卸载服务
            private void UninstallService()
            {
                if (IsServiceExisted())
                {
                    //停止服务
                    using (ServiceController control = new ServiceController(serviceName))
                    {
                        if (control.Status == ServiceControllerStatus.Running)
                        {
                            control.Stop();
                        }
                    }
                    //开始卸载
                    string[] args = new string[] { "/u", this.textServicePath.Text };
                    ManagedInstallerClass.InstallHelper(args);
                    MessageBox.Show("卸载成功!");
                }
                else
                {
                    MessageBox.Show("已卸载!");
                }
            }
    
            //查找项目下、安装目录下服务EXE文件路径
            private void btnFindExe_Click(object sender, EventArgs e)
            {
                string[] resultArray = Directory.GetFiles(Directory.GetCurrentDirectory(), "我的每日提醒项目.exe", SearchOption.AllDirectories);
                if (resultArray.Length > 0)
                {
                    this.textServicePath.Text = resultArray[0];
                }
            }
        }

    B-安装过程:

    准备资料:

    1-钉钉群组添加自定义机器人,生成webhook链接URL。 

    2-一个windows服务项目。

    3-一个管理服务安装,卸载,启动,停止的winform窗体项目。

    1-创建自定义机器人:

    在钉钉的群组里,有群机器人的入口进入,添加一个自定义机器人:

    添加成功后,会生成一个开发的webhook推送消息的接口地址:

     2-一个windows服务项目,以VS2015为例:

    在服务的设计图里,右键添加安装程序:

     安装程序如下:我们可以设置关于服务的一些说明和程序设置:

     说明相关:描述,显示名,服务名称

    服务程序账户设置:这里我们要选择本地系统

     至此一个服务的项目及安装程序就搭建起来了。

    3-一个管理服务安装,卸载,启动,停止的winform窗体项目:

    这里我只展示页面,具体创建很简单,就不多说了,我将安装和服务的启用,卸载和服务的停用写在一起了。

  • 相关阅读:
    Atitit 图像处理30大经典算法attilax总结
    Atitit 图像清晰度 模糊度 检测 识别 评价算法 源码实现attilax总结
    Atitit  rgb yuv  hsv HSL 模式和 HSV(HSB) 图像色彩空间的区别
    Atitit  从 RGB 到 HSL 或 HSV 的转换
    Atitit 图像清晰度 模糊度 检测 识别 评价算法 原理
    Atitit 修改密码的功能流程设计 attilax总结
    atitit 点播系统 概览 v2 qb1.docx
    Atitit dsl exer v3 qb3 新特性
    atitit.TokenService v3 qb1  token服务模块的设计 新特性.docx
    Atitit 异常机制与异常处理的原理与概论
  • 原文地址:https://www.cnblogs.com/lxhbky/p/10242839.html
Copyright © 2011-2022 走看看