一、概念名稱
Windows服務(即以前的 NT 服務),使您能夠創建在它們自己的Windows會話中可長時間運行的可執行應用程式,這些服務可以在計算機啟動時自動啟動,可以暫停和重新啟動而且不顯示任何用戶界面,這種服務非常適合在服務器上使用,或任何時候,為了不影響在同一臺計算機上作業的其他用戶,需要長時間運行功能時使用,
二、創建Windows服務
2.1、創建專案
新建->專案->Windows 桌面->Windows 服務,

專案右鍵屬性->應用程式->輸出型別,可以看出它是屬于"Windows 應用程式",

2.2、添加安裝程式
打開Service1.cs->空白處右鍵->添加安裝程式,

2.3、設定安裝資訊
打開ProjectInstaller.cs,

2.3.1、serviceInstaller1
點擊serviceInstaller1,在屬性中設定服務資訊,此示例是創建一個"HelloWorld"的服務,

說明:
Description:服務描述,直接顯示到Windows服務串列中的描述,
DisplayName:服務顯示名稱,直接顯示到Windows服務串列中的名稱,
ServiceName:服務名稱,啟動或停止服務時的標識,
StartType:啟動型別,如自動、手動等,
2.3.2、serviceProcessInstaller1
點擊serviceProcessInstaller1,在屬性中設定運行服務的賬戶型別,

2.4、生成專案
考慮到后面涉及到的Debugger除錯方法,此處選擇Release模式進行生成,

三、安裝與卸載服務
3.1、InstallUtil.exe
在VS安裝目錄下將InstallUtil.exe拷貝到專案的Release檔案夾下,InstallUtil.exe在VS2017的路徑為:C:\Windows\Microsoft.NET\Framework\v4.0.30319,
3.2、安裝服務
在Release檔案夾的地址欄中輸入"cmd"調出命令提示符表單:
安裝服務命令:
InstallUtil.exe LinkTo.Test.WindowsService.exe
啟動服務命令:
net start HelloWorld
當然,一般我們使用批處理的方式來安裝與卸載服務,
在Release檔案夾下面,創建一個"安裝服務.bat"的批處理檔案:
@echo off
echo===================================================
echo LinkTo.Test.WindowsService 正在安裝服務
echo===================================================
@echo off
InstallUtil.exe LinkTo.Test.WindowsService.exe
@echo off
echo===================================================
echo LinkTo.Test.WindowsService 正在啟動服務
echo===================================================
@echo off
net start HelloWorld
pause
在運行中輸入"services.msc"進入服務,即可看到新建的HelloWorld服務:

3.3、卸載服務
在Release檔案夾下面,創建一個"卸載服務.bat"的批處理檔案:
@echo off
echo===================================================
echo LinkTo.Test.WindowsService 正在停止服務
echo===================================================
@echo off
net stop HelloWorld
@echo off
echo===================================================
echo LinkTo.Test.WindowsService 正在卸載服務
echo===================================================
@echo off
InstallUtil.exe /u LinkTo.Test.WindowsService.exe
pause
四、服務定時器
一般來說,服務都會設定每隔多長時間執行一次任務,這里使用System.Threading.Timer來做個簡單的日志記錄,將日志寫入到Release\Log檔案夾下,
public partial class Service1 : ServiceBase { private static Timer timerAsync = null; private int dueTimeInterval = 1000 * 5; //單位:毫秒 private int periodInterval = 1000 * 5; //單位:毫秒 public Service1() { InitializeComponent(); //callback:一個 TimerCallback 委托,表示要執行的方法, //state:一個包含回呼方法要使用的資訊的物件,或者為空參考, //dueTime:呼叫 callback 之前延遲的時間量(以毫秒為單位),指定 Timeout.Infinite 以防止計時器開始計時,指定零(0)以立即啟動計時器, //period:呼叫 callback 的時間間隔(以毫秒為單位),指定 Timeout.Infinite 可以禁用定期終止, timerAsync = new Timer(AutoAsyncCallback, null, Timeout.Infinite, Timeout.Infinite); } /// <summary> /// 服務啟動 /// </summary> /// <param name="args"></param> protected override void OnStart(string[] args) { base.OnStart(args); timerAsync.Change(dueTimeInterval, periodInterval); WriteLog(DateTime.Now.ToString("HH:mm:ss") + " 服務啟動" + "\r\n"); WriteLog(Environment.NewLine); } /// <summary> /// 服務停止 /// </summary> protected override void OnStop() { base.OnStop(); if (timerAsync != null) { timerAsync.Change(Timeout.Infinite, Timeout.Infinite); timerAsync.Dispose(); timerAsync = null; } WriteLog(DateTime.Now.ToString("HH:mm:ss") + " 服務停止" + "\r\n"); WriteLog(Environment.NewLine); } /// <summary> /// 服務暫停 /// </summary> protected override void OnPause() { base.OnPause(); WriteLog(DateTime.Now.ToString("HH:mm:ss") + " 服務暫停" + "\r\n"); WriteLog(Environment.NewLine); } /// <summary> /// 計算機關閉 /// </summary> protected override void OnShutdown() { base.OnShutdown(); WriteLog(DateTime.Now.ToString("HH:mm:ss") + " 計算機關閉" + "\r\n"); WriteLog(Environment.NewLine); } /// <summary> /// 回呼函式 /// </summary> /// <param name="state"></param> private void AutoAsyncCallback(object state) { try { timerAsync.Change(Timeout.Infinite, Timeout.Infinite); #if DEBUG if (!Debugger.IsAttached) Debugger.Launch(); //當行程運行到這里的時候會自動停下來并彈出提示框 Debugger.Break(); //這個方法和在VS中加入紅色的斷點是一模一樣的 #endif WriteLog(DateTime.Now.ToString("HH:mm:ss") + " AutoAsyncCallback執行開始,執行緒ID = " + Thread.CurrentThread.ManagedThreadId + "\r\n"); Thread.Sleep(1000 * 10); //模擬耗時較長的計算任務,且耗時大于定時的間隔時間, } catch (Exception ex) { WriteLog(DateTime.Now.ToString("HH:mm:ss") + " AutoAsyncCallback執行例外:" + "\r\n" + ex.Message); } finally { timerAsync.Change(dueTimeInterval, periodInterval); WriteLog(DateTime.Now.ToString("HH:mm:ss") + " AutoAsyncCallback執行結束" + "\r\n"); WriteLog(Environment.NewLine); } } /// <summary> /// 日志記錄 /// </summary> /// <param name="logInfo">日志資訊</param> void WriteLog(string logInfo) { try { string logDirectory = AppDomain.CurrentDomain.BaseDirectory + "\\Log"; if (!Directory.Exists(logDirectory)) { Directory.CreateDirectory(logDirectory); } string filePath = logDirectory + "\\" + DateTime.Now.ToString("yyyy-MM-dd") + ".txt"; File.AppendAllText(filePath, logInfo); } catch { } } }Service1.cs
五、除錯服務
由于Windows服務程式不能直接執行,所以不能直接打斷點進行除錯,除錯服務的常用方式有以下兩種:
5.1、附加到行程
服務啟動后,點擊除錯->附加到行程->選擇LinkTo.Test.WindowsService->附加,

5.2、Debugger
#if DEBUG if (!Debugger.IsAttached) Debugger.Launch(); //當行程運行到這里的時候會自動停下來并彈出提示框 Debugger.Break(); //這個方法和在VS中加入紅色的斷點是一模一樣的 #endif
使用Debugger代碼進行除錯,在專案生成的時候,需使用Release模式,否則一直會有附加提示,可在配置管理器中修改Release模式,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/38323.html
標籤:C#
上一篇:C# 通過條件編譯來控制不同版本
