使用 Topshelf 框架來開發 Windows Service 專案,是一個相當不錯的選擇,他解決的版本更新總是又要用 sc.exe 重新安裝 Windows Service 以及 Debug 不易的問題。然而 Topshelf 框架本質是一個 Console 應用程式,這隻程式最終安裝到 Windows 服務控制管理器(SCM)中,而有時候我們會希望傳遞參數,然後根據參數值來啟動應用程式,但這樣的行為在 SCM 卻無法直接處理,因此要做到此功能,處理方式要稍微有點不一樣。
本篇作法將會修改 Windows 登陸檔,修改啟動 Windows Service 的執行參數,此方法不僅適用於 Topshelf 框架,也適用於其他開發 Windows Service 的方法。
舉個例子來說,我們要開發一個根據環境變數來切換商業邏輯的 Windows Service,但安裝該 Windows Service 的主機又不能設定環境變數時,很自然的想法就是透過啟動程式時,給他一個參數值,讓後續的商業邏輯能根據該參數值做調整。
在開發時期,我們要測試啟動時傳遞參數這件事情很簡單,可以在 Visual Studio 中設定 Application arguments 就好了(參考下圖設定 -env:Debug 的地方),但當你將程式安裝成 Windows Service 之後,你是無法直接在介面上手動設定啟動時的相關參數。
// 設定執行時所傳入的啟動參數 var env = string.Empty; configurator.AddCommandLineDefinition(nameof(env), value => { env = value; }); configurator.ApplyCommandLine();
這樣我們就可以在 Topshelf 中使用所傳進來的參數值。
執行 Windows Service 時加入啟動參數
前面有提到,安裝成 Windows Service 後,Windows 服務控制管理器會直接把該執行檔當作啟動指令,因此無法在後面添加參數,而且 Windows 服務控制管理器沒有介面讓我們去修改相關設定。
但 Windows 服務控制管理器會將啟動的路徑寫到 Windows 登陸檔裡面,以 DemoService 來說,登陸檔的路徑會是長這樣 Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\DemoService,而啟動路徑會放在這底下的 ImagePath 屬性中,你可以手動將啟動參數加進去裡面,這樣會讓 Windows 服務控制管理器在啟動該服務時,具有附加啟動參數的效果。