如何在安装后立即启动.NET Windows服务?

Jad*_*ias 86 .net installer windows-services

除了service.StartType = ServiceStartMode.Automatic我的服务在安装后没有启动

在我的ProjectInstaller上插入此代码

protected override void OnAfterInstall(System.Collections.IDictionary savedState)
{
    base.OnAfterInstall(savedState);
    using (var serviceController = new ServiceController(this.serviceInstaller1.ServiceName, Environment.MachineName))
        serviceController.Start();
}
Run Code Online (Sandbox Code Playgroud)

感谢ScottTx和Francis B.

Mat*_*vis 178

我已经张贴了一步一步的过程创建在C#中的Windows服务在这里.听起来你至少在这一点上,现在你想知道如何在安装后启动服务.将StartType属性设置为Automatic将导致服务在重新引导系统后自动启动,但它(如您所知)在安装后不会自动启动您的服务.

我不记得我最初在哪里找到它(也许是Marc Gravell?),但我确实找到了一个在线解决方案,允许您通过实际运行服务来安装和启动服务.这是一步一步的:

  1. Main()像这样构建你的服务功能:

    static void Main(string[] args)
    {
        if (args.Length == 0) {
            // Run your service normally.
            ServiceBase[] ServicesToRun = new ServiceBase[] {new YourService()};
            ServiceBase.Run(ServicesToRun);
        } else if (args.Length == 1) {
            switch (args[0]) {
                case "-install":
                    InstallService();
                    StartService();
                    break;
                case "-uninstall":
                    StopService();
                    UninstallService();
                    break;
                default:
                    throw new NotImplementedException();
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 这是支持代码:

    using System.Collections;
    using System.Configuration.Install;
    using System.ServiceProcess;
    
    private static bool IsInstalled()
    {
        using (ServiceController controller = 
            new ServiceController("YourServiceName")) {
            try {
                ServiceControllerStatus status = controller.Status;
            } catch {
                return false;
            }
            return true;
        }
    }
    
    private static bool IsRunning()
    {
        using (ServiceController controller = 
            new ServiceController("YourServiceName")) {
            if (!IsInstalled()) return false;
            return (controller.Status == ServiceControllerStatus.Running);
        }
    }
    
    private static AssemblyInstaller GetInstaller()
    {
        AssemblyInstaller installer = new AssemblyInstaller(
            typeof(YourServiceType).Assembly, null);
        installer.UseNewContext = true;
        return installer;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 继续支持代码......

    private static void InstallService()
    {
        if (IsInstalled()) return;
    
        try {
            using (AssemblyInstaller installer = GetInstaller()) {
                IDictionary state = new Hashtable();
                try {
                    installer.Install(state);
                    installer.Commit(state);
                } catch {
                    try {
                        installer.Rollback(state);
                    } catch { }
                    throw;
                }
            }
        } catch {
            throw;
        }
    }
    
    private static void UninstallService()
    {
        if ( !IsInstalled() ) return;
        try {
            using ( AssemblyInstaller installer = GetInstaller() ) {
                IDictionary state = new Hashtable();
                try {
                    installer.Uninstall( state );
                } catch {
                    throw;
                }
            }
        } catch {
            throw;
        }
    }
    
    private static void StartService()
    {
        if ( !IsInstalled() ) return;
    
        using (ServiceController controller = 
            new ServiceController("YourServiceName")) {
            try {
                if ( controller.Status != ServiceControllerStatus.Running ) {
                    controller.Start();
                    controller.WaitForStatus( ServiceControllerStatus.Running, 
                        TimeSpan.FromSeconds( 10 ) );
                }
            } catch {
                throw;
            }
        }
    }
    
    private static void StopService()
    {
        if ( !IsInstalled() ) return;
        using ( ServiceController controller = 
            new ServiceController("YourServiceName")) {
            try {
                if ( controller.Status != ServiceControllerStatus.Stopped ) {
                    controller.Stop();
                    controller.WaitForStatus( ServiceControllerStatus.Stopped, 
                         TimeSpan.FromSeconds( 10 ) );
                }
            } catch {
                throw;
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 此时,在目标计算机上安装服务后,只需使用-install命令行参数从命令行(与任何普通应用程序一样)运行服务即可安装并启动服务.

我想我已经涵盖了所有内容,但如果您发现这不起作用,请告诉我,以便我可以更新答案.

  • 请注意,此解决方案不需要使用InstallUtil.exe,因此您不必将其作为安装程序的一部分提供. (12认同)
  • 回滚会将数据写入控制台.至于空的catch块,它是一个调试的东西.我可以在throw语句中放置一个断点来检查可能发生的任何异常. (4认同)
  • 我收到错误错误:无法找到类型或命名空间名称'YourServiceType'(您是否缺少using指令或程序集引用? (4认同)
  • `YourServiceType`是你添加到服务中的`ProjectInstaller`,它包含`ServiceInstaller`和`ServiceProcessInstaller` (4认同)
  • 空的"catch {throw;}"条款有什么意义?此外,通过"Rollback()"隐藏故障可能不是一个好主意,因为这种情况基本上会使系统处于未定义状态(我猜你想要安装服务,在中间的某个地方失败并且无法撤消它) ).您至少应该"向用户"显示有可疑的东西 - 或者Rollback()函数是否将某些消息写入控制台? (2认同)
  • @Rashmin Javiya 为什么非技术人员会手动安装甚至开发 Windows 服务? (2认同)

Sco*_*tTx 22

您可以在服务可执行文件中执行此操作,以响应从InstallUtil进程触发的事件.重写OnAfterInstall事件以使用ServiceController类来启动服务.

http://msdn.microsoft.com/en-us/library/system.serviceprocess.serviceinstaller.aspx

  • 这是一个很好的解决方案,但仍然需要使用InstallUtil实用程序.如果您已经将InstallUtil作为安装的一部分提供,那么这是最有意义的.但是,如果您想放弃打包InstallUtil,请使用命令行解决方案. (3认同)

Fra*_* B. 7

视觉工作室

如果要使用VS创建安装项目,则可以创建一个调用.NET方法来启动服务的自定义操作.但是,实际上并不建议在MSI中使用托管自定义操作.看到这个页面.

ServiceController controller  = new ServiceController();
controller.MachineName = "";//The machine where the service is installed;
controller.ServiceName = "";//The name of your service installed in Windows Services;
controller.Start();
Run Code Online (Sandbox Code Playgroud)

InstallShield或Wise

如果您使用的是InstallShield或Wise,则这些应用程序提供启动服务的选项.对于Wise的示例,您必须添加服务控制操作.在此操作中,您可以指定是否要启动或停止服务.

维克斯

使用Wix,您需要在服务组件下添加以下xml代码.有关这方面的更多信息,您可以查看此页面.

<ServiceInstall 
    Id="ServiceInstaller"  
    Type="ownProcess"  
    Vital="yes"  
    Name=""  
    DisplayName=""  
    Description=""  
    Start="auto"  
    Account="LocalSystem"   
    ErrorControl="ignore"   
    Interactive="no">  
        <ServiceDependency Id="????"/> ///Add any dependancy to your service  
</ServiceInstall>
Run Code Online (Sandbox Code Playgroud)


Otá*_*cio 6

您需要使用EXE的组件名称或批处理(sc start)作为源,在MSI中的'ExecuteImmediate'序列末尾添加自定义操作.我认为这不能用Visual Studio完成,你可能必须使用真正的MSI创作工具.


Mat*_*att 5

要在安装后立即启动它,我会生成一个包含installutil的批处理文件,然后是sc start

它并不理想,但它有效......


Sco*_*tTx 5

使用.NET ServiceController类启动它,或发出命令行命令启动它 - "net start servicename".无论哪种方式都有效.


gok*_*ter 5

要添加到ScottTx的答案,如果您使用Microsoft方式(即使用安装项目等),这是启动服务的实际代码.

(请原谅VB.net代码,但这就是我所坚持的)

Private Sub ServiceInstaller1_AfterInstall(ByVal sender As System.Object, ByVal e As System.Configuration.Install.InstallEventArgs) Handles ServiceInstaller1.AfterInstall
    Dim sc As New ServiceController()
    sc.ServiceName = ServiceInstaller1.ServiceName

    If sc.Status = ServiceControllerStatus.Stopped Then
        Try
            ' Start the service, and wait until its status is "Running".
            sc.Start()
            sc.WaitForStatus(ServiceControllerStatus.Running)

            ' TODO: log status of service here: sc.Status
        Catch ex As Exception
            ' TODO: log an error here: "Could not start service: ex.Message"
            Throw
        End Try
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

要创建上述事件处理程序,请转到2个控件所在的ProjectInstaller设计器.单击ServiceInstaller1控件.转到事件下的属性窗口,您将在那里找到AfterInstall事件.

注意:不要将上面的代码放在ServiceProcessInstaller1的AfterInstall事件下.根据经验,这是行不通的.:)