採訪/編輯:
棒!城市編輯部
更新時間:
2019-03-11 18:12
發佈時間:
2017-11-06 08:33
分享:
累積人次:
154

[Windows Service]使用.Net / C#撰寫Windows Service應用程式(可在Windows背景執行的服務)

Windows Service(Windows 服務)主要是一種長期執行的應用程式,可以在電腦啟動時自動執行服務,且不會顯示任何UI介面來影響使用者,非常適合背景長期執行功能時使用。

 

 

 

1. 「Windows Service」專案建立範例

建立專案:使用 Visual Studio 2012 開發工具,從建立專案開始

檔案 -> 新增 -> 專案

在「新增專案」視窗選擇

Visual C# -> Windows 桌面 -> Windows 服務   (也就是所謂的 Windows Service 啦!)

視窗下方四個輸入框,依序輸入:

1. 名稱:MyService1。(輸入我們想要新增的專案名稱,我們使用 MyService1 作為範例)

2. 位置:C:\MacBookPro\Projects\。(預設)

3. 方案:建立新方案。(預設)

4. 方案名稱:MyService1。(預設)

並且勾選「為方案建立目錄」(預設)

接著按下「確定」即可以完成專案建立。

其中,「名稱」也就是未來的「服務名稱」,同一台電腦的服務名稱不可以有重覆。

如果,發現「服務名稱」重覆時,可以在「屬性」視窗中,找到「ServiceName」。(其他的參數用預設的就可以了)

 

建立專案後會產生預設服務MyService1類別,該類別繼承自System.ServiceProcess.ServiceBase服務基礎類別。

由於此預設服務僅能啟動與停止,因此僅需要複寫OnStart及OnStop()方法即可;

若調整CanPauseAndContinue為true時則表示此服務可被暫停與繼續,所以就有複寫OnPause()及OnContinue()方法的必要。

 

建立專案後,「方案總管」視窗,這裡可以發現這個「Windows 服務」專案和一般專案視窗有些不同

除了一樣有 Program.cs,還多了一個 Service1.cs

右鍵 Service1.cs 選擇「設計工具檢視」點選後,開啟會看到下面的畫面

視窗裡什麼都沒有,Windows 服務,只需要元件不需要有畫面

這時候,檢查屬性參數列表如下:

 

直接按「開始」按鈕執行的話會看到跳出錯誤提示視窗,因為它是服務,所以無法直接執行

 換句話說,這個「服務」專案需要安裝才可以執行

 

 

 

2. 專案相關設定

到這裡還沒有開始寫排程器,還要爲這個服務做一些設定

回到Service1.cs的「設計工具檢視」的視窗中點選右鍵,並點選「加入安裝程式」

  

這時會多一個ProjectInstaller.cs檔案,在「設計工具檢視」下會有「serviceProessInstaller1」「serviceInstaller1」二個檔案。

2.1 點選 serviceInstaller1,在屬性視窗修改參數

  

這裡需要做一些設定

DisplayName 就是服務要顯示的名稱

Description 服務描述

ServiceName 服務的唯一名稱

StartType 啓動方式,預設值是Manual (手動)、為了讓服務自動啟動所以改選「Automatic」。

DelayedAutoStart 爲開機之後是否延遲啓動

 

2.2 點選 serviceProcessInstaller1,在屬性視窗修改參數

  

設定只要改一個

Account 這裡決定服務的帳號與權限

我們可以設定爲LocalSystem (就是最大權限)

 

 

 

 

3. 「Windows Service」程式撰寫

在專案視窗選擇「Service1」檔案雙擊,或是右鍵選「檢視程式碼」,

開啟程式碼視窗後,就可以開始編撰程式了。

點選視窗中的「請按這裡切畫到程式碼檢視」、或右鍵 Service1.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;

namespace MyProject1
{
    public partial class MyService1?: ServiceBase
    {
        public MyService1()
        {
            InitializeComponent();
        }
        protected override void OnStart(string[] args)
        {
        }
        protected override void OnStop()
        {
        }
    }
}


只有很簡單的OnStart跟OnStop

 

3.1 首先撰寫定時器

這裡用到 System.Timers 所以要先引用

using System.Timers;

 

3.2 定義一個定時器屬性

private Timer MyTimer;

public Service1()

{

    InitializeComponent();

}

protected override void OnStart(string[] args)

{

    MyTimer = new Timer();

    MyTimer.Elapsed += new ElapsedEventHandler(MyTimer_Elapsed);

    MyTimer.Interval = 10 * 1000;

    MyTimer.Start();

}

撰寫屬於我們的一個方法程式,

private void MyTimer_Elapsed(object sender, ElapsedEventArgs e)

{

    // Do SomeThing...

}

3.3 撰寫一個每一個小時執行一次的事件紀錄日誌的服務程式

在專案視窗選擇「Service1」檔案右鍵選「設計工具檢視」,也就是設計模式,

在「工具箱」視窗,選擇「元件」中的「EventLog」拖曳到設計模式視窗中,

3.4 回到Service1「程式碼」

 

public Service1()

{

    InitializeComponent();

    this.AutoLog = false;

    if (!System.Diagnostics.EventLog.SourceExists("MySource"))

    {

        System.Diagnostics.EventLog.CreateEventSource("MySource", "MyLog");

    }

    eventLog1.Source = "MySource";

}

protected override void OnStart(string[] args)

{

    eventLog1.WriteEntry("Start Timer.");

    MyTimer = new Timer();

    MyTimer.Elapsed += new ElapsedEventHandler(MyTimer_Elapsed);

    MyTimer.Interval = 60 * 60 * 1000;

    MyTimer.Start();

}

private void MyTimer_Elapsed(object sender, ElapsedEventArgs e)

{

    eventLog1.WriteEntry("Timer Ticked.");

}

protected override void OnStop()

{

    eventLog1.WriteEntry("Stop Timer.");

    MyTimer.Stop();

    MyTimer = null;

}

 

 

 

 

 

4. 安裝 / 解除安裝 服務

4.1 安裝服務執行指令 installutil.exe

官方文件提到安裝服務的時候執行指令 installutil.exe

在命令提示字元輸入:InstallUtil MyService1.exe

解除安裝的時候執行指令:InstallUtil /u MyService1.exe

而「installutil.exe」版本需要配合所使用的 .Net Framework 版本,我們本次開發的範例使用的是 .Net Framework 4.5,所以使用 v4.0.30319

在其所在的資料夾打開後,也會看到這個版本的 installutil.exe 檔案

C:\Windows\Microsoft.NET\Framework\<版本號>

註:如果你是其他的.Net Framework版本,打開相關版本資料也會看到 installutil.exe 檔案。

4.2 安裝權限

 

在前面服務屬性中,Account = LocalSystem

所以使用「系統管理員執行」。

 

4.3 安裝指令:

註:Account = LocalSystem,也就是需要管理員權限

@ECHO OFF

net session >nul 2>&1
IF NOT %ERRORLEVEL% EQU 0 (
   ECHO ERROR: Please run Bat as Administrator.
   PAUSE
   EXIT /B 1
)

@SETLOCAL enableextensions
@CD /d "%~dp0"

 

 

REM The following directory is for .NET 4
SET DOTNETFX4=%SystemRoot%\Microsoft.NET\Framework\v4.0.30319
SET PATH=%PATH%;%DOTNETFX4%

ECHO Installing MyService1...
ECHO ---------------------------------------------------
InstallUtil /i .\MyService1.exe
ECHO ---------------------------------------------------
ECHO Done.

PAUSE

 

 

 

5. 執行測試

完成之後可以做安裝,然後做測試

在Install-MyService1.bat按右鍵 -> Run as administrator

Screen Shot 2014-02-03 at 9.16.09 PM   

打開控制台 -> 系統管理工具 -> 服務

這個列表裡面就會多了一個你的服務

Screen Shot 2014-02-03 at 9.24.25 PM

 

裡面的名稱都跟剛剛打的一樣

 Screen Shot 2014-02-03 at 9.24.41 PM  

 

那我們剛剛寫的日誌呢?

控制台 -> 系統管理工具 -> 事件檢視器

找到Applications and Services (應用程式及服務記錄檔)

就會多出一個MyLog

裡面就是我們寫的日誌檔

Screen Shot 2014-02-03 at 9.29.35 PM  

 

 

 

6. 除錯

之前在重複若干次的 安裝服務/解除安裝服務 的時候

有遇到EventLog的問題

可以嘗試去登錄編輯器(regedit)刪除以下機碼

HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\services\eventlog\MySource
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\services\MySource
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\MySource
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\MySource

在執行 解除安裝服務 的程式

 

 

 

參考資料:

http://blog.wahahajk.com/2008/06/cservice.html
http://msdn.microsoft.com/en-us/library/y817hyb6(v=vs.110).aspx
http://gogo1119.pixnet.net/blog/post/27575780-%5Bc%23%5D-windows-service%E5%BB%BA%E7%AB%8B%E7%AF%84%E4%BE%8B
http://www.cnblogs.com/xianspace/archive/2009/04/05/1429835.html

http://stackoverflow.com/questions/3307151/receiving-has-already-been-registered-from-eventlog-createeventsource-ev
http://stackoverflow.com/questions/4824051/problem-installing-windows-service