使用C#除錯Windows服務模板專案
Windows服務是非常強大的應用程式,可用於在backgorund中執行許多不同型別的任務。他們可以在不需要任何使用者登入的情況下啟動,並且可以使用除登入使用者之外的其他使用者帳戶執行。但是,如果通過遵循常規服務開發步驟開發Windows服務應用程式,即使在開發環境中也難以除錯。
本文提出了一種不使用任何服務開發庫(如Topshelf)開發Windows服務的不同方法,以便在開發階段輕鬆監視和除錯。
特徵
示例專案具有以下功能;
- 它在除錯模式下作為控制檯應用程式執行,在釋出模式下作為常規Windows服務執行。
- 根據日誌型別在控制檯上顯示具有不同文字顏色的日誌訊息。
- Windows服務相關操作和實際後臺任務處理操作是分開的,因此可以輕鬆地對實際服務操作進行單元測試。
- 可以使用InstallUtil.exe安裝和解除安裝服務。但是您不需要安裝它來進行測試和除錯。
準備此應用程式的步驟
示例專案網站原始碼是使用Visual Studio 2017準備的。
1-建立Windows服務專案
在Visual Studio中,單擊“檔案”\“新建”\“專案”。選擇“Visual C#\ Windows桌面\ Windows服務”專案型別。
2-將專案輸出型別從Windows應用程式更改為控制檯應用程式
右鍵單擊專案名稱並選擇“屬性”,開啟專案屬性。
從“輸出型別”選擇列表中選擇控制檯應用程式。
3-安裝log4net軟體包
從Package Manager控制檯或Manage Nuget Packages選單選項安裝log4net nuget軟體包。
4-配置log4net
log4net是一個非常強大的日誌庫,可以將日誌寫入許多目標,如文字檔案,控制檯,資料庫,Windows事件日誌,甚至可以將它們作為電子郵件傳送。這些日誌編寫器(或目標)稱為“appender”。log4net配置必須至少有一個appender,但它可能有很多。每個appender都有自己的設定。
log4net配置可以新增到app.config檔案中,也可以是單獨的檔案。我更喜歡單獨的檔案方法,因此為log4net新增兩個配置檔案,用於除錯和釋出模式。名稱無關緊要,您可以將它們命名為“ log4net.debug.config ”和“ log4net.prod.config ”。Debug配置檔案有兩個appender; RollingFileAppender
ColoredConsoleAppender
。生產配置檔案還有兩個appender; RollingFileAppender
和 EventLog
。但 EventLog
appender已註釋掉,如果要編寫Windows事件日誌,可以取消註釋。
最小日誌級別在<root>
元素下定義為<level>
配置元素。對於除錯配置級別是DEBUG,對於生產它是INFO
。有效等級是; DEBUG
,INFO
,WARN
,ERROR
。有關詳細資訊,請參閱log4net文件。
下一步配置步驟是告訴log4net庫在除錯和釋放模式下使用哪個檔案。為此,請開啟AssemblyInfo.cs檔案併為log4net新增程式集級別屬性。新增這些行以在除錯和釋放模式下在兩個檔案之間切換。
#if DEBUG [ assembly:log4net.Config.XmlConfigurator(ConfigFile = “ log4net.debug.config”,Watch = true)] #else [ assembly:log4net.Config.XmlConfigurator(ConfigFile = “ log4net.prod.config”,Watch = 真的)] #endif
5-新增SampleBackgroundService類,其中包含我們的Windows服務將執行的實際後臺操作。
它是一個非常簡單的類 Start
,Stop
用於啟動和停止後臺任務處理執行緒的方法以及連續寫入日誌的執行緒方法。
class SampleBackgroundService { // 從log4net獲取此類的記錄器LogManager private static ILog logger = LogManager.GetLogger(typeof(SampleBackgroundService)); // 啟動執行緒 public void Start(){...} // 停止執行緒 public void Stop(){...} // 執行後臺任務並寫入日誌的服務執行緒 private void serviceThread() { while(!stopRequested) { // 寫出不同型別的日誌...... } } }
6-更新自動生成的Windows Service類中的程式碼
我已將自動新增的Windows Services類重新命名為 SampleWindowsService
。此類繼承自ServiceBase
,並且是在啟動或停止Windows服務時呼叫其方法OnStart
和類的類OnStop
。該類僅建立類的例項 SampleBackgroundService
並呼叫其Start
和Stop
方法。
7-更新Program.cs檔案中的Main mathod,使其在Debug和Release模式下表現不同
建立新的Windows服務專案時,自動生成的Main方法包含用於建立和啟動自動生成的Windows服務的程式碼。但是,Windows服務無法作為常規應用程式啟動和託管。因此,當您嘗試執行該應用程式時會出現一條錯誤訊息。
要執行和測試我們的應用程式,我們不需要建立真正的Windows服務例項,因為除了建立和啟動SampleBackgroundService
類的例項之外,它不包含任何程式碼 。Main方法中更新的程式碼在SampleBackgroundService
Debug模式下建立並啟動類的例項, 並作為控制檯應用程式執行。但是在釋出模式下建立並執行真正的Windows服務。
static void Main() { ILog logger = LogManager.GetLogger(typeof(Program)); #if DEBUG //在除錯模式下作為常規控制檯應用程式執行 // 手動建立SampleBackgroundService類的例項並呼叫其start方法 logger.Info(“正在啟動服務......”); SampleBackgroundService _backgroundService = new SampleBackgroundService (); _backgroundService.Start(); logger.Info(“ 服務已啟動。按Enter鍵停止...”); 到Console.ReadLine(); logger.Info(“ 停止服務......”); _backgroundService.Stop(); logger.Info(“已停止。”); #else //在Release模式 ServiceBase [] ServicesToRun中建立並執行真正的Windows服務例項 ; ServicesToRun = new ServiceBase [] { 新的 SampleWindowsService() }; ServiceBase.Run(ServicesToRun); #endif }
8-新增Service Installer元件,以便能夠使用InstallUtil.exe安裝此服務
要新增安裝程式元件,請在解決方案資源管理器上雙擊SampleWindowsService.cs。它將顯示服務的設計檢視。
右鍵單擊設計區域,然後單擊上下文選單中的“新增安裝程式”。
這會將ProjectInstaller.cs和設計器檔案新增到專案中。刪除自動生成的程式碼 ProjectInstaller.InitializeComponent()
方法和自動生成的變數(serviceProcessInstaller1
,serviceInstaller1
)。
將以下程式碼新增到 ProjectInstaller.cs檔案中;
public partial class ProjectInstaller:Installer { public const string SERVICE_NAME = “ Sample Background Service” ; private readonly ServiceProcessInstaller m_ServiceProcessInstaller; private readonly ServiceInstaller m_ServiceInstaller; public ProjectInstaller() { // 安裝程序的安裝程式(在本例中為'DebuggableWindowsService.exe') // 只能有一個ServiceProcessInstaller m_ServiceProcessInstaller = new ServiceProcessInstaller(); m_ServiceProcessInstaller.Account = ServiceAccount.LocalSystem; // 在應用程式中註冊實際Windows服務實現的安裝程式 // 可能有一個或多個ServiceInstaller m_ServiceInstaller = new ServiceInstaller(); m_ServiceInstaller.ServiceName = SERVICE_NAME; m_ServiceInstaller.Description = “ ” ; m_ServiceInstaller.StartType = ServiceStartMode.Automatic; m_ServiceInstaller.DelayedAutoStart = true ; Installers.Add(m_ServiceProcessInstaller); Installers.Add(m_ServiceInstaller); 的InitializeComponent(); } // ... }
如果要在安裝服務之前和之後執行任何任務,可以覆蓋適當的基本方法,例如 OnBeforeInstall
, OnBeforeUninstall
...
您無需安裝(或向Windows服務登錄檔註冊服務)您的服務即可執行和除錯。但是,如果需要,可以使用InstallUtil.exe來安裝和解除安裝服務。InstallUtil.exe位於.NET Framework安裝資料夾下。例如,“ C:\ Windows \ Microsoft.NET \ Framework \ v4.0.30319 ”
要註冊該服務,請開啟命令列視窗並使用可執行檔案的完整路徑執行InstallUtil.exe。您可能需要“以管理員身份”執行命令列窗口才能註冊服務。
C :\ Windows \ Microsoft.NET \ Framework \ v4.0.30319> InstallUtil.exe“D:\ DebuggableWindowsService \ src \ bin \ Release \ DebuggableWindowsService.exe”
要解除安裝服務,請使用/ u選項執行相同的命令。
C :\ Windows \ Microsoft.NET \ Framework \ v4.0.30319> InstallUtil.exe / u“D:\ DebuggableWindowsService \ src \ bin \ Release \ DebuggableWindowsService.exe”
9-在除錯模式下執行應用程式以檢視日誌輸出和除錯
下面是在除錯模式下執行應用程式時顯示的示例輸出。
關於Windows服務的重要說明
Windows Service應用程式在幾個方面與其他常規應用程式不同。因此,應用程式在除錯(控制檯應用程式模式)和釋出(Windows服務模式)模式下的行為可能不同。
首先,當您在除錯模式下執行應用程式時,其工作目錄將是可執行檔案所在的路徑。例如“ D:\ DebuggableWindowsService \ src \ bin \ Release \ DebuggableWindowsService.exe ”
但是,當您使用InstallUtil.exe或安裝應用程式安裝它並從Windows服務管理應用程式執行它時,其工作目錄將是“ C:\ Windows \ System32 ”或“ C:\ Windows \ SysWOW64 ”,具體取決於您的服務是64位32d無論是在32位還是64位Windows上執行。
如果要在安裝目錄中讀取或寫入檔案而不是系統目錄,則可以在啟動時使用工作目錄。例如;
Environment.CurrentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly()。Location);
其次, Windows服務可以使用除登入使用者之外的其他使用者帳戶執行。當應用程式rusn作為真正的Windows服務時,某些在除錯模式下執行的操作可能無法執行。這些操作的示例是訪問目錄或網路路徑,開啟埠......
第三, Windows服務沒有使用者介面,通常無法顯示使用者介面。Windows作業系統阻止了他們對顯示卡的訪問。遺憾的是,無法使用Windows服務中的強大GPU。要了解有關此限制的更多資訊,請搜尋“會話0隔離