使用C#開發windows服務定時發消息到釘釘羣_羣組簡單消息

前言:本提醒服務,是由C#語言開發的,主要由windows服務項目和winform項目組成,運行服務可實現功能:向釘釘自定義機器人羣組裏,定時,定次,推送多個自定義消息內容,並實現主要功能的日誌記錄。  能夠說功能強大!!!web

 

備註: 本文主要2部分:1-關鍵代碼,2-安裝步驟。   windows

 

A-關鍵代碼:多線程

1-服務:ide

 

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") + "\r\n");
                    strBuilder.Append("上班記得打卡!打卡遲到時間不能大於60分鐘,多1分鐘扣10塊!\r\n");
                    strBuilder.Append("上班記得佩戴胸牌!被抓住一次扣30塊錢!\r\n");
                }
                else
                {
                    strBuilder.Append("如今時間是:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\r\n");
                    strBuilder.Append("下班記得打卡!\r\n");
                }


                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}:\r\n", 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}】:\r\n", webItem.WebsiteName, (i + 1));
                            strBuilder.AppendFormat("ID:{0}\nLogType:{1}\nCreateTime:{2}\nLogContent:{3}\nUrl:{4}\r\n", 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,任務內容,任務的開始時間,任務時間間隔,任務已執行次數,任務最大執行次數)。網站

 

重點:服務運行後會造成一個單例模式,計時器,及服務幫助類的全部屬性的初始化值,均會存在該單例中,所以咱們能夠將每一個任務的信息記錄在每一個任務的實例中去,這樣更合理;另外在任務執行時,新增了多線程的使用來處理任務的準時和執行次數問題。ui

本來走過一些彎路:本來TimeCycel類中沒有任務已執行次數屬性,我是經過一個方法計算的:當前時間-任務開始時間/任務執行間隔,計算的,可是這個方式計算存在時延問題以及任務的執行快慢,沒法保證執行次數和執行間隔的準確性,使用每一個任務的實例單獨統計快捷方便,保證了已執行次數的準確性。this

 

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代碼:spa

 

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窗體項目:

這裏我只展現頁面,具體建立很簡單,就很少說了,我將安裝和服務的啓用,卸載和服務的停用寫在一塊兒了。

 

相關文章
相關標籤/搜索