Windows Service - 建立簡單的Windows Service

在我們需要執行程式跑一些繁瑣的工作,而且執行時間又超長的時候,如果一直有個視窗在旁邊,做其他事情一定會覺得卡卡的,或會怕不小心關閉視窗。又或者有些工作我想要開機時自動在背景執行。這些情況下你可以可慮建置一個在背景執行的Windows Service,今天限量就要來輕鬆建置一個簡單的Windows Service


1. 首先在 [方案] 裡建立一個 Windows Service 的 [專案]



2. 建立專案後會預設建立 Service1 的 Class,限量把它改成 TestService。接著打開 TestService.cs,在 Design 的視窗中按下右鍵,點選 [Add Installer]



3. ProjectInstaller 是一段將服務安裝在機器上的程式,定義了一些服務名稱, 描述...等基本的資訊。在 [Add Installer] 之後就會產生 ProjectInstaller 類別,如下圖:



4. ServiceInstaller 算是這個服務的自我介紹一樣,我們可以在 ServiceInstaller 的屬性視窗裡修改一些資料,限量修改了服務描述, 服務顯示名稱, 與服務名稱,這三個屬性會在Windows的服務管理與工作管理員出現。另外,StartType 為啟動選項,預設是手動(Manual),當然還有自動(Automatic,作業系統啟動後啟動), 無法啟動(Disable,使用者無法啟動), 還有系統啟動(System)與開機啟動(Boot),這兩個是裝置驅動程式專用的,所以我們比較少會用到。



5. ServiceProcessInstaller 是這個服務的安裝程式,它負責將這個服務安裝到機器上,這裡要修改 Account 屬性。Account 有4個選項(User, LocalService, LocalSystem, NetworkService)。User 代表特定的使用者,使用 User 的時候會要求輸入使用者的帳密;LocalService的層級與User 相同,差異在於 LocalService 是匿名認證,不被安全機制所控管;LocalSystem則擁有最高權限;NetworkService層級介於LocalSystem與User和LocalService之間(詳細說明請見參考來源)。這裡限量就直接使用LocalSystem。




6. 調整完安裝程式後,我們就來加 Service 的 Code 吧!

TestService.cs
using System.Diagnostics;
using System.ServiceProcess;

namespace Capital.Test.ServiceApp
{
    public partial class TestService : ServiceBase
    {
        private static readonly string LOG_NAME = "LimitedServiceLog";
        private static readonly string LOG_SOURCE = "TestService";
        private EventLog _logger;

        public TestService()
        {
            InitializeComponent();
            _logger = new EventLog(LOG_NAME);
            if (!EventLog.SourceExists(LOG_SOURCE))
            {
                EventLog.CreateEventSource(LOG_SOURCE, LOG_NAME);
            }
            _logger.Source = LOG_SOURCE;
        }

        protected override void OnStart(string[] args)
        {
            _logger.WriteEntry("LimitedTestService Start", EventLogEntryType.Information);
        }

        protected override void OnStop()
        {
            _logger.WriteEntry("LimitedTestService Stop", EventLogEntryType.Information);
        }
    }
}

因為 Service 本身就有提供 EventLog 的 Log 功能,所以限量就直接產生一個 EventLog 的實體方便寫入事件檢視器裡。Service 屬於常駐型的背景程式,在 ServiceBase 裡提供了一些生命週期的事件(OnStart, OnStop, OnPause, OnContinue...等),這些都可以透過 Override 來加入,增加使用的彈性。

7. 為了讓我們的服務能在 Build 過後直接安裝,限量在專案的 [Build Events] 加入了安裝服務的指令,這樣就省得在打指令安裝。以下為重新安裝指令(注意:在服務存在的情況下是無法在安裝該服務的,所以要先解除安裝再重新安裝)
C:\Windows\Microsoft.NET\Framework\v4.0.30319\installutil.exe /u $(TargetFileName)
C:\Windows\Microsoft.NET\Framework\v4.0.30319\installutil.exe $(TargetFileName)



8. 編譯我們的程式碼發現在 Output 視窗中可以看到系統安裝服務的相關資訊。





9. 確認服務安裝好後,接著我們就要來去[控制台] => [系統管理工具] => [服務] 確定服務是否安裝,如果有的話就來執行看看。



注意:在重新安裝服務(重新Compiler)的時候,記得要把服務管理視窗關掉,否則會無法安裝成功,會出現以下錯誤訊息:
安裝階段中發生例外狀況。
System.ComponentModel.Win32Exception: 指定的服務已標註刪除。

另外,我們也可以從工作管理員去啟動我們的服務。


10. 等看到服務狀態為執行中後,再來就到 [控制台] => [系統管理工具] => [事件檢視器] 裏頭看看服務的 Log 有沒有寫進去就OK了。


學會了服務的建置方式後,以後一些繁瑣的事情(像轉檔, 倒資料)就可以讓服務自己在背景執行不會影響到使用者的作業了。

參考來源:
MSDN - 逐步解說:在元件設計工具中建立 Windows 服務應用程式
MSDN - Service User Accounts





留言