C#管理windows服務

.NET Framework中提供了現成的類庫能夠很方便的實現對windows服務的安裝、卸載、啓動、中止、獲取運行狀態等功能。這些類都在System.ServiceProcess命名空間下。windows

安裝window服務

using (AssemblyInstaller installer = new AssemblyInstaller())
{
     installer.UseNewContext = true;
     installer.Path = serviceFilePath;    //serviceFilePath是windows服務可執行文件的完整路徑
     IDictionary savedState = new Hashtable();
     installer.Install(savedState);
     installer.Commit(savedState);
 }

 

卸載windows服務

using (AssemblyInstaller installer = new AssemblyInstaller())
{
    installer.UseNewContext = true;
    installer.Path = serviceFilePath;
     installer.Uninstall(null);
 }

 

啓動windows服務

//使用ServiceController.GetServices()可獲取windows服務列表,進而可判斷服務是否存在

//serviceName是註冊的windows服務名稱

using (ServiceController control = new ServiceController(serviceName))
 {
     if (control.Status == ServiceControllerStatus.Stopped)
     {
         control.Start();
     }
 }

 

一切都彷佛很簡單,略坑的是,ServiceController.Start方法(注意並非StartAsync),看起來是一個同步方法,若是服務啓動失敗,按理會異常拋出。而實際狀況卻時,Start方法是當即返回的,不會等待服務的啓動結果。方法註釋裏發生異常只有兩種情形:spa

System.ComponentModel.Win32Exception: 訪問系統 API 時出錯。線程

System.InvalidOperationException: 未找到服務。日誌

至於其它情形致使的啓動失敗(如文件缺失、服務應用程序內部出錯),Start方法一無所知。code

ServiceController類有一個Wait方法,做用是阻塞當前線程等待服務到達指定的狀態,還能夠設置等待的超時時間,這有必定的用處,但並不理想。當啓動失敗的時候,如何可以獲取到啓動失敗的信息呢?orm

 

一個猥瑣的辦法

windows服務啓動不管成功仍是失敗,都會記錄一條windows日誌,能夠藉助對windows日誌的監控來實現:blog

在調用ServiceController.Start方法以前,啓動對windows日誌的監聽:事件

_eventLog = new EventLog("Application");
 _eventLog.EnableRaisingEvents = true;
 _eventLog.EntryWritten += Log_EntryWritten;

在EntryWritten事件處理器裏,判斷windows日誌類型,進而得知windows服務啓動狀況:開發

private void Log_EntryWritten(object sender, EntryWrittenEventArgs e)
 {
     EventLogEntry log = e.Entry;
     if(log.Source == _currentSection.ServiceName)
    {
        if(log.EntryType == EventLogEntryType.Information)
         {
            //啓動成功
        }
        else
        {
           //啓動失敗
            MessageBox.Show(log.Message);
        }
         _eventLog.Dispose();
         _eventLog = null;
     }
 }


這裏還一個略坑的點,按通常的事件開發約定,sender參數應該就是發生事件的主體,在這裏想來應該就是EventLog類的實例,然而事實上sender是EventLogInternal類的實例,很遺憾的是,這個類並不公開訪問,並且,也並未發現有跟EventLog類的直接關聯。同步

相關文章
相關標籤/搜索