Windows Service是一種沒有UI,開機後不需使用者登入就會執行的應用程式,通常會用來做一些定時排程的工作。
用C#開發Windows Service很簡單,以下用一個簡單的範例來介紹
首先開一個新專案,名稱為MyService
[![](http://4.bp.blogspot.com/-nPZ1TWcF_gE/UtyZHPYoD6I/AAAAAAAAA5U/PmOegTcO0ZQ/s1600/01.NewProject.png)](http://4.bp.blogspot.com/-nPZ1TWcF_gE/UtyZHPYoD6I/AAAAAAAAA5U/PmOegTcO0ZQ/s1600/01.NewProject.png)
在方案總管中可以看到,只有Program.cs和Service1.cs兩個檔案
[![](http://3.bp.blogspot.com/-67GklNvhUr4/UtyZTsHucXI/AAAAAAAAA5c/tGlNpdjspvM/s1600/02.%E6%96%B9%E6%A1%88%E7%B8%BD%E7%AE%A1.png)](http://3.bp.blogspot.com/-67GklNvhUr4/UtyZTsHucXI/AAAAAAAAA5c/tGlNpdjspvM/s1600/02.%E6%96%B9%E6%A1%88%E7%B8%BD%E7%AE%A1.png)
先來看看Program.cs,這是應用程式的進入點,主要是透過ServiceBase.Run來啟動服務
using System.ServiceProcess;
namespace MyService
{
static class Program
{
/// <summary>
/// 應用程式的主要進入點。
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
}
}
}
再來看一下Service1.cs,可以看到是繼承自ServiceBase的類別,再自行覆寫要處理的事件
using System.ServiceProcess;
namespace MyService
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
}
}
}
可覆寫的方法如下
OnContinue | 指定暫停服務後要繼續正常運作所要執行的動作 |
OnCustomCommand | 指定在具有指定參數值的命令發生時所要執行的動作
需要注意命令編號為128~256 |
OnPause | 指定在服務暫停時所要執行的動作 |
OnPowerEvent | 這適用於攜帶型電腦,當它們進入暫停模式的時候,不同於系統關閉 |
OnSessionChange | 當從 Terminal Server 工作階段接收到變更事件時執行 |
OnShutdown | 指定緊接在系統關閉之前應該發生的處理 |
OnStart | 指定在服務啟動時所要執行的動作 |
OnStop | 指定在服務停止執行時所要執行的動作 |
可設定的屬性如下,最常用的還是ServiceName這個屬性
更詳細的內容可以參考MSDN關於[ServiceBase](http://msdn.microsoft.com/zh-tw/library/system.serviceprocess.servicebase(v=vs.110).aspx)的介紹
先來簡單地寫個定時功能
透過Log元件輸出目前時間到Log2Console
相關內容可以參考之前的筆記
[Common.Logging](http://blog.developer.idv.tw/2013/12/commonlogging.html)
[好用的LogViewer](http://blog.developer.idv.tw/2013/11/logviewer.html)
using System;
using System.ServiceProcess;
using System.Timers;
using Common.Logging;
namespace MyService
{
public partial class Service1 : ServiceBase
{
private Timer timer;
private ILog log;
private string datetimeFormat = “yyyy/MM/dd HH:mm:ss”;
private double timerInterval = 1000;
public Service1()
{
InitializeComponent();
this.log = LogManager.GetLogger(typeof(Service1));
this.timer = new Timer();
this.timer.Interval = this.timerInterval;
this.timer.AutoReset = false;
this.timer.Enabled = false;
this.timer.Elapsed += Timer_Elapsed;
}
protected override void OnStart(string[] args)
{
this.timer.Enabled = true;
}
protected override void OnStop()
{
this.timer.Enabled = false;
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
this.timer.Stop();
try
{
this.log.TraceFormat("now:{0}", DateTime.Now.ToString(this.datetimeFormat));
}
catch (Exception ex)
{
this.log.Error(ex);
}
this.timer.Start();
}
}
}
接下來要增加安裝程式,在Service1.cs的設計畫面按右鍵,選擇加入安裝程式
會增加一個繼承自System.Configuration.Install.Installer的ProjectInstaller類別
[![](http://3.bp.blogspot.com/-UKW0EPYGkkk/UtybMznln5I/AAAAAAAAA6A/aoHnh0w5gwU/s1600/05.Projectnstaller.png)](http://3.bp.blogspot.com/-UKW0EPYGkkk/UtybMznln5I/AAAAAAAAA6A/aoHnh0w5gwU/s1600/05.Projectnstaller.png)
先設定服務執行時使用的帳號,比較安全的帳號是NetworkService,如果有需要存取資源的話,再去允許權限或是改用LocalSystem這個帳號
[![](http://1.bp.blogspot.com/-CYoBSMIfZj4/Utybkt47AiI/AAAAAAAAA6Q/9Y5H4xUtBd4/s1600/06.%E7%99%BB%E5%85%A5%E5%B8%B3%E8%99%9F.png)](http://1.bp.blogspot.com/-CYoBSMIfZj4/Utybkt47AiI/AAAAAAAAA6Q/9Y5H4xUtBd4/s1600/06.%E7%99%BB%E5%85%A5%E5%B8%B3%E8%99%9F.png)
接下來設定服務的啟動方式,最常用的當然是自動啟動
[![](http://2.bp.blogspot.com/-iS03_xS0ewU/UtyfYhnVFPI/AAAAAAAAA68/CN4arzq-Q3Y/s1600/07.AotuMatic.png)](http://2.bp.blogspot.com/-iS03_xS0ewU/UtyfYhnVFPI/AAAAAAAAA68/CN4arzq-Q3Y/s1600/07.AotuMatic.png)
DisplayName是名稱,Description描述
[![](http://2.bp.blogspot.com/-sK3GlrDv3cQ/Utybu00xq_I/AAAAAAAAA6g/_omh1Cvm4xA/s1600/08.%E5%90%8D%E7%A8%B1%E6%8F%8F%E8%BF%B0.png)](http://2.bp.blogspot.com/-sK3GlrDv3cQ/Utybu00xq_I/AAAAAAAAA6g/_omh1Cvm4xA/s1600/08.%E5%90%8D%E7%A8%B1%E6%8F%8F%E8%BF%B0.png)
設定好後就完成這個Service,編譯後產生執行檔,接下來就要把這個服務安裝的到作業系統中
比較正規的作法是去新增一個安裝專案,但為了方便開發起見,以下用批次檔的方式來安裝
新增幾個批次檔,並改成永遠複製
[![](http://2.bp.blogspot.com/-IeOUENSgG7I/Uty35k-diyI/AAAAAAAAA7g/X4PkkxCTMZc/s1600/13.batfile.png)](http://2.bp.blogspot.com/-IeOUENSgG7I/Uty35k-diyI/AAAAAAAAA7g/X4PkkxCTMZc/s1600/13.batfile.png)
install.bat用來安裝
@echo off
set InstallUtil=%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe
if not exist %InstallUtil% set InstallUtil=%WINDIR%\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe
if not exist %InstallUtil% set InstallUtil=%WINDIR%\Microsoft.NET\Framework\v3.5\InstallUtil.exe
if not exist %InstallUtil% (
echo InstallUtil.exe not found
exit
)
%InstallUtil% -i MyService.exe
restart.bat用來重新啟動服務
net stop Service1
net start Service1
start.bat用來啟動服務
stop.bat用來停止服務
uninstall.bat用來反安裝
@echo off
set InstallUtil=%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe
if not exist %InstallUtil% set InstallUtil=%WINDIR%\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe
if not exist %InstallUtil% set InstallUtil=%WINDIR%\Microsoft.NET\Framework\v3.5\InstallUtil.exe
if not exist %InstallUtil% (
echo InstallUtil.exe not found
exit
)
%InstallUtil% -u MyService.exe
注意檔案編碼為ANSI格式,UTF8格式在command pro中執行會有亂碼
批次檔是透過InstallUtil.exe這個工具程式來安裝和反安裝,詳細的參數請參考
MSDN的說明
點擊install.bat,安裝成功
[![](http://3.bp.blogspot.com/-c0GwQkAtsis/Uty3Z7jSevI/AAAAAAAAA7Y/v7dRgrQqiMc/s1600/11.install.png)](http://3.bp.blogspot.com/-c0GwQkAtsis/Uty3Z7jSevI/AAAAAAAAA7Y/v7dRgrQqiMc/s1600/11.install.png)
點繫start.bat,啟動服務
[![](http://3.bp.blogspot.com/-OuMwHcWUqPA/UtzKFtatI2I/AAAAAAAAA7w/yqZ3XtmwBH8/s1600/14.Start.png)](http://3.bp.blogspot.com/-OuMwHcWUqPA/UtzKFtatI2I/AAAAAAAAA7w/yqZ3XtmwBH8/s1600/14.Start.png)
順利的話就可以在Log2Console中定時收到目前時間
[![](http://1.bp.blogspot.com/-6L01sHTG9Ws/UtzKQtBQroI/AAAAAAAAA74/hGzL_CENGSk/s1600/15.run.png)](http://1.bp.blogspot.com/-6L01sHTG9Ws/UtzKQtBQroI/AAAAAAAAA74/hGzL_CENGSk/s1600/15.run.png)
要移除服務就點擊uninstall.bat,反安裝成功
[![](http://3.bp.blogspot.com/-D4bFUIA_Kfk/Utyb6S2DsJI/AAAAAAAAA6w/H9_s_cUU95E/s1600/12.uninstall.png)](http://3.bp.blogspot.com/-D4bFUIA_Kfk/Utyb6S2DsJI/AAAAAAAAA6w/H9_s_cUU95E/s1600/12.uninstall.png)
Sharing is caring!