使用C#調試Windows服務模板項目

Windows服務是非常強大的應用程序,可用於在backgorund中執行許多不同類型的任務。他們可以在不需要任何用戶登錄的情況下啓動,並且可以使用除登錄用戶之外的其他用戶帳戶運行。但是,如果通過遵循常規服務開發步驟開發Windows服務應用程序,即使在開發環境中也難以調試。

本文提出了一種不使用任何服務開發庫(如Topshelf)開發Windows服務的不同方法,以便在開發階段輕鬆監視和調試。

特徵
示例項目具有以下功能;

它在調試模式下作爲控制檯應用程序運行網站源碼,在發佈模式下作爲常規Windows服務運行。
根據日誌類型在控制檯上顯示具有不同文本顏色的日誌消息。
Windows服務相關操作和實際後臺任務處理操作是分開的,因此可以輕鬆地對實際服務操作進行單元測試。
可以使用InstallUtil.exe安裝和卸載服務。但是您不需要安裝它來進行測試和調試。
準備此應用程序的步驟
示例項目是使用Visual Studio 2017準備的。

1-創建Windows服務項目
在Visual Studio中,單擊“文件”“新建”“項目”。選擇“Visual C# Windows桌面 Windows服務”項目類型。

使用C#調試Windows服務模板項目

2-將項目輸出類型從Windows應用程序更改爲控制檯應用程序
右鍵單擊項目名稱並選擇“屬性”,打開項目屬性。

從“輸出類型”選擇列表中選擇控制檯應用程序。

使用C#調試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。但 EventLogappender已註釋掉,如果要編寫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方法中更新的代碼在SampleBackgroundServiceDebug模式下創建並啓動類的實例, 並作爲控制檯應用程序運行。但是在發佈模式下創建並運行真正的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。它將顯示服務的設計視圖。

右鍵單擊設計區域,然後單擊上下文菜單中的“添加安裝程序”。

使用C#調試Windows服務模板項目

這會將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-在調試模式下運行應用程序以查看日誌輸出和調試

下面是在調試模式下運行應用程序時顯示的示例輸出。

使用C#調試Windows服務模板項目

關於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隔離”。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章