C#管理windows服务

2021-02-12 16:18

阅读:506

.NET Framework中提供了现成的类库可以很方便的实现对windows服务的安装、卸载、启动、停止、获取运行状态等功能。这些类都在System.ServiceProcess命名空间下。

安装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方法是立即返回的,不会等待服务的启动结果。方法注释里发生异常只有两种情形:

System.ComponentModel.Win32Exception: 访问系统 API 时出错。

System.InvalidOperationException: 未找到服务。

至于其它情形导致的启动失败(如文件缺失、服务应用程序内部出错),Start方法一无所知。

ServiceController类有一个Wait方法,作用是阻塞当前线程等待服务到达指定的状态,还可以设置等待的超时时间,这有一定的用处,但并不理想。当启动失败的时候,如何能够获取到启动失败的信息呢?

 

一个猥琐的办法

windows服务启动无论成功还是失败,都会记录一条windows日志,可以借助对windows日志的监控来实现:

在调用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类的直接关联。


评论


亲,登录后才可以留言!