C#:創建最簡單的Windows服務以及實現定時任務(使用Quartz組件)

以下開發一個最簡單的Windows服務,並設置定時任務,可以在指定時間自動執行業務。

先預覽下Demo項目完成後的文件結構如下

1.創建windows服務項目

文件-》新建--》項目,選擇"Windows服務",確定。

2.引用定時任務組件Quartz

右擊項目-》管理NuGet程序包 查詢quartz,安裝對應版本。(當前默認是最新穩定版3.07需要.net4.52以上版本,不過我係統是4.5不支持,最後選擇了2.62安裝)

3.創建service

新建完項目會默認創建一個服務文件,本項目是WechatService.cs,雙擊該文件-》在設計頁面右擊-》選擇“添加安裝程序”。

點擊serviceInstaller1,可以再屬性頁設置服務的相關參數,DisplayName是系統服務列表中顯示的服務名,Description是服務描述。

設置完成後即可開始在服務文件WechatService.cs中編寫服務執行的相關代碼。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Quartz;
using Quartz.Impl;
using Quartz.Xml;
using Quartz.Simpl;
using log4net;
using Common;

namespace gszh.wx.winservice
{
    public partial class WechatService : ServiceBase
    {
/
        private static ILog log = LogManager.GetLogger(typeof(WechatService));
        private IScheduler scheduler;

        public WechatService()
        {
            InitializeComponent();
            //定時器Quartz
            try
            {
                scheduler = new StdSchedulerFactory().GetScheduler();
                XMLSchedulingDataProcessor process = new XMLSchedulingDataProcessor(new SimpleTypeLoadHelper());
                //讀取定時任務配置xml文件
                Stream sr = new StreamReader(com.MapPath("/config/quartzJob.xml")).BaseStream;
                process.ProcessStream(sr, null);
                process.ScheduleJobs(scheduler);
                log.Debug("定時器啓動.");
            }
            catch (Exception e)
            {
                log.Debug(e.ToString());
            }
        }

        protected override void OnStart(string[] args)
        {
            scheduler.Start();
            log.Debug("服務運行成功");
        }

        protected override void OnStop()
        {
            if (scheduler!=null)
            {
                scheduler.Shutdown(false);
            }
            log.Debug("服務運行停止");
        }
    }
}

代碼中的quartzJob.xml是定時配置文件,後面會介紹配置。

4.配置定時任務文件參數

quartzJob.xml文件主要是用於設置服務運行期間,到達指定時間後自動執行業務功能。文件內容如下:

<?xml version="1.0" encoding="utf-8" ?>
<!-- This file contains job definitions in schema version 2.0 format -->

<job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0">
  <processing-directives>
    <overwrite-existing-data>true</overwrite-existing-data>
  </processing-directives>
  <schedule>
    <!--Myjob Start-->
    <job>
      <name>Myjob</name>
      <group>JobGroup</group>
      <description>測試定時任務</description>
      <job-type>gszh.wx.winservice.Myjob,gszh.wx.winservice</job-type>
      <durable>true</durable>
      <recover>false</recover>
    </job>
    <trigger>
      <cron>
        <name>TestTrigger</name>
        <group>TriggerGroup</group>
        <job-name>Myjob</job-name>
        <job-group>JobGroup</job-group>
        <start-time>2019-10-10T08:00:00+18:00</start-time>
        <cron-expression>0 0/1 * * * ?</cron-expression>
      </cron>
    </trigger>
    <!--Myjob End-->
  </schedule>
</job-scheduling-data>

其中<job-type>gszh.wx.winservice.Myjob,gszh.wx.winservice</job-type>節點配置中,gszh.wx.winservice.Myjob是業務具體實現類的完全類名,gszh.wx.winservice是命名空間

<cron-expression>0 0/1 * * * ?</cron-expression>是crom表達式,此處代表每分鐘執行一次

5.業務具體實現類

新建一個類gszh.wx.winservice.Myjob,此類要實現Quartz.IJob的接口Execute,在這個接口裏編寫具體業務功能。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Quartz;
using log4net;
using Common;

namespace gszh.wx.winservice
{
    [PersistJobDataAfterExecution]//保存執行狀態
    [DisallowConcurrentExecution]//不允許併發執行
    public class Myjob : IJob
    {
        private static ILog log = LogManager.GetLogger("Myjob");
        public void Execute(IJobExecutionContext context)
        {
            log.Debug("任務執行..");
        }
    }
}

至此,一個最簡單的windows服務已經創建完成,接下來就是要安裝到系統中。

6.部署服務

開發完的服務程序,需要安裝到系統中才能運行,微軟提供了工具,

詳見https://docs.microsoft.com/zh-cn/dotnet/framework/windows-services/how-to-install-and-uninstall-services?redirectedfrom=MSDN

但本Demo使用一個很簡易的Winform程序來執行安裝服務的功能。

winform的界面和代碼如下

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Collections;
using System.ServiceProcess;
using System.Configuration.Install;
using log4net;

namespace WechatServiceClient
{
    public partial class frmMain : Form
    {
        string serviceName ;
        string serviceFilePath ;
        private static ILog log = LogManager.GetLogger(typeof(frmMain));
        public frmMain()
        {
            InitializeComponent();
            serviceName = "WechatGszhService";
            //服務程序所在位置
            serviceFilePath = Application.StartupPath + "\\gszh.wx.winservice.exe";
        }

        
        private void btnInstall_Click(object sender, EventArgs e)
        {
            string msg = "";
            try
            {
                if (this.IsServiceExisted(serviceName))
                {
                    msg = "該服務已經存在,請先卸載後再安裝.";
                    log.Debug(msg);
                    MessageBox.Show(msg, "提示", MessageBoxButtons.OK);
                }
                else
                {
                    this.InstallService(serviceFilePath);
                    msg = "服務安裝完成.";
                    log.Debug(msg);
                    MessageBox.Show(msg, "提示", MessageBoxButtons.OK);
                } 
            }
            catch (Exception ex)
            {
                log.Debug(ex.ToString());
            }
        }

        private void btnUninstall_Click(object sender, EventArgs e)
        {
            if (this.IsServiceExisted(serviceName))
            {
                this.ServiceStop(serviceName);
                this.UninstallService(serviceFilePath);
                string msg = "服務卸載完成.";
                log.Debug(msg);
                MessageBox.Show(msg, "提示", MessageBoxButtons.OK);
            }
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            if (this.IsServiceExisted(serviceName))
                this.ServiceStart(serviceName);
            string msg = "服務啓動完成.";
            log.Debug(msg);
            MessageBox.Show(msg, "提示", MessageBoxButtons.OK);
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            if (this.IsServiceExisted(serviceName)) this.ServiceStop(serviceName);
            string msg = "服務已暫停.";
            log.Debug(msg);
            MessageBox.Show(msg, "提示", MessageBoxButtons.OK);
        }
        //判斷服務是否存在
        private bool IsServiceExisted(string serviceName)
        {
            ServiceController[] services = ServiceController.GetServices();
            foreach (ServiceController sc in services)
            {
                if (sc.ServiceName.ToLower() == serviceName.ToLower())
                {
                    return true;
                }
            }
            return false;
        }

        //安裝服務
        private void InstallService(string serviceFilePath)
        {
            using (AssemblyInstaller installer = new AssemblyInstaller())
            {
                installer.UseNewContext = true;
                installer.Path = serviceFilePath;
                IDictionary savedState = new Hashtable();
                installer.Install(savedState);
                installer.Commit(savedState);
            }
        }

        //卸載服務
        private void UninstallService(string serviceFilePath)
        {
            using (AssemblyInstaller installer = new AssemblyInstaller())
            {
                installer.UseNewContext = true;
                installer.Path = serviceFilePath;
                installer.Uninstall(null);
            }
        }
        //啓動服務
        private void ServiceStart(string serviceName)
        {
            using (ServiceController control = new ServiceController(serviceName))
            {
                if (control.Status == ServiceControllerStatus.Stopped)
                {
                    control.Start();
                }
            }
        }

        //停止服務
        private void ServiceStop(string serviceName)
        {
            using (ServiceController control = new ServiceController(serviceName))
            {
                if (control.Status == ServiceControllerStatus.Running)
                {
                    control.Stop();
                }
            }
        }
    }
}

7.運行服務

winform程序編譯後,將生成的exe文件複製到服務程序所在目錄運行。即可對服務進行安裝、卸載、啓動、暫停等操作。

 8.調試服務

先運行服務,然後在VS的菜單“調試”-》“附加到進程”,選中你的應用服務進程名後確定附加。接下來就可以按平常的調試步驟,設定好斷點,運行調試功能。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章