Windows服務是非常強大的應用程式,可用於在backgorund中執行許多不同類型的任務。他們可以在不需要任何用戶登錄的情況下啟動,並且可以使用除登錄用戶之外的其他用戶帳戶運行。但是,如果通過遵循常規服務開發步驟開發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隔離”。