在采集程序中增加定時發送郵件以及關機處理的實現


我們在采集特定數據的時候,往往需要耗費較長的時間,有時候因為一些事情,不可能長久的在電腦前等待結果,那么需要程序在一段時間后自動給我們發送郵件等通知,以及執行退出程序或者關機等處理善后工作,以節省資源或者電源,那么需要實現這個過程是如何的呢。本篇隨筆基於這個采集程序的基礎上增加這些功能的實現,介紹其中的一些處理技巧。

1、郵件配置

如果我們需要實現發送郵件、或者發送短信等通知途徑,那么我們就需要把這些處理過程涉及到的參數提前錄入到系統里面,是在不行硬編碼也行,不過為了可擴展性,我傾向於使用配置界面進行參數的配置。

在關於參數配置的處理,我在博客《Winform開發框架之參數配置管理功能實現-基於SettingsProvider.net的構建》以及《Winform界面中實現菜單列表的動態個性化配置管理》都做了比較詳細的介紹,基於SettingsProvider.net的封裝處理,能夠實現我們很方便的配置功能,可以配置在XML文件中,也可以保存在數據庫中,根據需要處理。

那么我這里為了采集發送數據的需要,也需要配置一個郵件的信息,如下界面所示。

這個里面放置額外的兩個功能按鈕,一個是郵箱設置參考,一個是發送測試郵件,前者用來輔助填入一些參數,后者是驗證用戶賬號是否收到測試郵件。

發送測試郵件成功后,我們驗證下是否收到,以便核對下提供的參數是否正確。

 

 

2、設置定時處理

完成上面的步驟后,我們基本上完成了一半的工作量了,剩下的就是在合適的時間,讓系統發送通知給我們以及善后處理即可。

那么我們如果定時的話,需要指定一個時間范圍,使用DevExpress的TimeSpanEdit控件就合適不過了,我們只需要確定小時:分鍾:秒的數據后,就可以根據這個時間范圍確定我們執行任務的最終時間了。

這個彈出的小窗體,我們只用來獲取用戶輸入的時間范圍即可,沒有什么具體的邏輯。

輸入關機時間后,那么我們就可以根據關機時間,彈出一個倒計時的窗體,覆蓋在主程序的界面上。

最終我們到達時間的觸發點后,實現發送郵件通知以及退出程序或者關機的處理。

以上是整個處理的過程,那么實現的處理代碼是如何的呢,我們來分析下具體的代碼過程。

        private bool isShutdown = false;
        private TimerHelper timerHelper;
        private void btnSendAndShutdown_Click(object sender, EventArgs e)
        {
            btnSendAndShutdown.Enabled = false;
            try
            {
                if (!isShutdown)
                {
                    //獲取關機的時間
                    FrmShutdownTime frmTime = new FrmShutdownTime();
                    if (frmTime.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                        return;

                    //轉換為最終的時間
                    TimeSpan timeSpan = frmTime.timeShutdown.TimeSpan;
                    this.endTime = DateTime.Now.Add(timeSpan);

                    //定時器輔助類處理定時工作
                    timerHelper = new TimerHelper(1000, true);
                    timerHelper.Execute += () =>
                    {
                        //每隔一秒對事件進行處理判斷
                        if (ShutdownEvent != null)
                        {
                            ShutdownEvent(sender, e);
                        }
                    };

                    //顯示關機面板
                    groupShutdown.BringToFront();
                    groupShutdown.Visible = true;
                }
                else
                {
                    //關閉面板
                    CloseShutDownGroup();
                }

                isShutdown = !isShutdown;
                this.btnSendAndShutdown.Text = isShutdown ? "取消關機處理" : "定時發送郵件后關機";
            }
            finally
            {
                btnSendAndShutdown.Enabled = true;
            }
        }

上面主要的處理邏輯,放在了定時器的處理事件上

ShutdownEvent(sender, e);

這個觸發的事件,是我們在主窗體定義的一個事件,目的就是用來實現倒計時及發送通知用的。

        private event EventHandler ShutdownEvent;

然后我們在窗體里面初始化這個事件處理即可,初始化代碼如下所示。

            //關閉或者退出程序的事件
            this.ShutdownEvent += (s, e)=>
            {
                #region 定時處理操作
                this.Invoke(new MethodInvoker(delegate()
                {
                    //判斷當前的剩余時間是否進入通知流程
                    var ts = endTime.Subtract(DateTime.Now);
                    if (ts.TotalSeconds > 1)
                    {
                        //更新倒計時
                        timeLeft.TimeSpan = new TimeSpan(ts.Days, ts.Hours, ts.Minutes, ts.Seconds);
                    }
                    else
                    {
                        //關閉面板並退出定時器
                        CloseShutDownGroup();

                        //執行發送郵件操作
                        SendMail();

                        //關閉主機或者退出程序
                        if (chkShutdown.Checked)
                        {
                            Process.Start("shutdown.exe", "-s");//關機
                        }
                        else if (chkExitApp.Checked)
                        {
                            Application.ExitThread();
                        }
                    }
                }));
                #endregion

最終的邏輯就是發送郵件和退出程序或者關機的處理

    //執行發送郵件操作
    SendMail();

    //關閉主機或者退出程序
    if (chkShutdown.Checked)
    {
        Process.Start("shutdown.exe", "-s");//關機
    }
    else if (chkExitApp.Checked)
    {
        Application.ExitThread();
    }

關機的操作,我們用來執行命令行的方式實現關機的處理,非常方便。

關於這個Shutdown命令的處理,我下面列出它的一些功能說明。

shutdown命令的參數:

shutdown.exe -s:關機
shutdown.exe -r:關機並重啟
shutdown.exe -l:注銷當前用戶

shutdown.exe -s -t 時間:設置關機倒計時
shutdown.exe -h:休眠
shutdown.exe -t 時間:設置關機倒計時。默認值是 30 秒。
shutdown.exe -a:取消關機
shutdown.exe -f:強行關閉應用程序而沒有警告
shutdown.exe -m \計算機名:控制遠程計算機
shutdown.exe -i:顯示“遠程關機”圖形用戶界面,但必須是Shutdown的第一個參數
shutdown.exe -c "消息內容":輸入關機對話框中的消息內容
shutdown.exe -d [u][p]:xx:yy :列出系統關閉的原因代碼:u 是用戶代碼 ,p 是一個計划的關閉代碼 ,xx 是一個主要原因代碼(小於 256 的正整數) ,yy 是一個次要原因代碼(小於 65536 的正整數)

比如你的電腦要在12:00關機,可以選擇“開始→運行”,輸入“at 12:00 Shutdown -s",這樣,到了12點電腦就會出現“系統關機”對話框,默認有30秒鍾的倒計時並提示你保存工作。
如果你想以倒計時的方式關機,可以輸入 “Shutdown.exe -s -t 3600",這里表示60分鍾后自動關機,“3600"代表60分鍾。

而發送郵件,我們一般利用一個郵件發送的封裝類處理下即可。

        /// <summary>
        /// 發送郵件
        /// </summary>
        private bool SendMail()
        {
            //統計數據
            btnSumaryData_Click(null, null);

            string title = string.Format("{0}期統計結果-{1}", Portal.gc.CurrentQSNumber, DateTime.Now);

            //獲取控件展示的內容,並把它的換行轉換下
            List<string> list = new List<string>();
            list.AddRange(txtShenxiao.Lines);
            list.AddRange(this.txtShenxiao2.Lines);
            string content = string.Join("<br>", list);

            //發送郵件
            var success = SendMailHelper.SendMail(title, content);
            return success;
        }

發送郵件的時候,我們先獲取用戶的郵件配置信息,然后調用郵件發送輔助類實現內容的發送處理,具體代碼如下所示。

    public class SendMailHelper
    {
        /// <summary>
        /// 發送郵件結果
        /// </summary>
        public static bool SendMail(string title, string content)
        {
            //獲取配置的郵件信息
            string creator = "";// LoginUserInfo.Name;
            ISettingsStorage store = new DatabaseStorage(creator);
            SettingsProvider settings = new SettingsProvider(store);

            bool result = false;
            EmailParameter parameter = settings.GetSettings<EmailParameter>();
            if (parameter != null)
            {
                //使用郵件輔助類,實現郵件內容的發送
                EmailHelper email = new EmailHelper(parameter.SmtpServer, parameter.LoginId, parameter.Password);
                email.Subject = title;
                email.Body = content;
                email.IsHtml = true;
                email.Charset = "gb2312";
                email.From = parameter.Email;
                email.FromName = parameter.Email;
                email.AddRecipient(parameter.Email);
                result = email.SendEmail();
            }
            return result;
        }

 

以上就是整個處理的過程,其中還涉及到了在線程間訪問控件的方式,如下代碼所示。

這個詳細的介紹可以參考我較早期的隨筆《淺談多線程中數據的綁定和賦值》,這些細節都需要我們一步步測試並尋找最佳的方案實現,希望這個隨筆的思路給你有一定的啟發。

當然,如果系統做的比較大一些,系統化一些的話,還可以考慮利用EasyNetQ的這種方式實現信息的通知。

這種通知可以更好的擴展,詳細介紹可以參考下隨筆《使用EasyNetQ組件操作RabbitMQ消息隊列服務》,不過一般小程序的就不用那么麻煩了,用一個定時器來處理下就可以了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM