• C#管理windows服务


    .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类的直接关联。

  • 相关阅读:
    mybatis显示sql语句 log4j.properties配置文件
    Netty 4.0 demo
    Netty多线程处理机制
    crontab定时任务中文乱码问题
    linux grep、find 命令详解
    resin access.log format配置详解
    linux top命令详解
    正则表达式介绍及案例分享
    java定时任务
    rhApp遇到的项目问题
  • 原文地址:https://www.cnblogs.com/sdlfx/p/8471710.html
Copyright © 2020-2023  润新知