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


88

除了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();
}

感谢ScottTx和FrancisB。


它不是在安装后立即启动,还是在重新启动时不启动?
克里斯·范欧普斯塔

Answers:


21

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

http://msdn.microsoft.com/zh-CN/library/system.serviceprocess.serviceinstaller.aspx


3
这是一个不错的解决方案,但仍然需要使用InstallUtil实用程序。如果您已经在安装过程中提供了InstallUtil,则最有意义。但是,如果要放弃打包InstallUtil,请使用命令行解决方案。
马特·戴维斯

181

我在此处发布了使用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();
            }
        }
    }
  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;
    }
  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;
            }
        }
    }
  4. 此时,在将服务安装到目标计算机上之后,只需使用-install命令行参数从命令行(如任何普通应用程序)运行服务以安装并启动服务。

我认为我已经涵盖了所有内容,但是如果您发现此操作无效,请告诉我,以便我更新答案。


12
请注意,此解决方案不需要使用InstallUtil.exe,因此您不必将其作为安装程序的一部分提供。
马特·戴维斯

2
空的“ catch {throw;}”子句有什么意义?另外,通过“ Rollback()”隐藏故障可能不是一个好主意,因为这种情况基本上会使系统处于未定义状态(我试过安装服务,在中间某处发生故障,无法撤消它) )。您至少应该“向”用户“显示出一些可疑的东西”-还是Rollback()函数将一些消息写入控制台?
Christian.K,

5
回滚确实会将数据写入控制台。至于空的catch块,这是调试的事情。我可以在throw语句上放置一个断点,以检查可能发生的任何异常。
马特·戴维斯

4
我收到错误错误:无法找到类型或名称空间名称“ YourServiceType”(您是否缺少using指令或程序集引用?
Yogesh 2013年

5
YourServiceTypeProjectInstaller您添加到服务中的内容,包含ServiceInstallerServiceProcessInstaller
bansi 2013年

6

视觉工作室

如果要使用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();

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>

5

您需要使用EXE的组件名称或批处理(sc开始)作为源,将自定义操作添加到MSI中“ ExecuteImmediate”序列的末尾。我认为无法使用Visual Studio做到这一点,您可能需要为此使用真正的MSI创作工具。


4

为了在安装后立即启动它,我先生成一个带有installutil的批处理文件,然后再执行sc start

这不是理想的方法,但是可以。


4

使用.NET ServiceController类来启动它,或发出命令行命令来启动它---“ net start servicename”。不管哪种方法。


4

要添加到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

要创建上述事件处理程序,请转到2个控件所在的ProjectInstaller设计器。单击ServiceInstaller1控件。转到事件下的属性窗口,然后在其中找到AfterInstall事件。

注意:请勿将以上代码放在ServiceProcessInstaller1的AfterInstall事件下。来自经验,这是行不通的。:)


VB.net代码还不错!对于使用多种语言工作的我们来说,不必从C转换代码就好了!
史蒂夫·里德

谢谢,这帮助我弄清楚了如何自动启动服务。
查尔斯·欧文

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.