Comment faire démarrer un service Windows .NET juste après l'installation?

88

Outre le service.StartType = ServiceStartMode.Automatic mon service ne démarre pas après l'installation

Solution

Inséré ce code sur mon ProjectInstaller

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

Merci à ScottTx et Francis B.

Jader Dias
la source
Il ne démarre pas juste après l'installation ou ne démarre pas lorsque vous redémarrez?
Chris Van Opstal

Réponses:

21

Vous pouvez tout faire à partir de votre exécutable de service en réponse aux événements déclenchés par le processus InstallUtil. Remplacez l'événement OnAfterInstall pour utiliser une classe ServiceController pour démarrer le service.

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

ScottTx
la source
3
C'est une solution intéressante, mais nécessite toujours l'utilisation de l'utilitaire InstallUtil. Si vous fournissez déjà InstallUtil dans le cadre de votre installation, cela est le plus logique. Mais, si vous souhaitez renoncer à empaqueter InstallUtil, utilisez la solution de ligne de commande.
Matt Davis
181

J'ai publié une procédure étape par étape pour créer un service Windows en C # ici . On dirait que vous êtes au moins à ce point, et maintenant vous vous demandez comment démarrer le service une fois qu'il est installé. Si vous définissez la propriété StartType sur Automatique, le service démarrera automatiquement après le redémarrage de votre système, mais il ne démarrera pas automatiquement (comme vous l'avez découvert) votre service après l'installation.

Je ne me souviens pas où je l'ai trouvé à l'origine (peut-être Marc Gravell?), Mais j'ai trouvé une solution en ligne qui vous permet d'installer et de démarrer votre service en exécutant réellement votre service lui-même. Voici l'étape par étape:

  1. Structurez la Main()fonction de votre service comme ceci:

    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. Voici le code de support:

    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. Continuer avec le code de support ...

    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. À ce stade, après avoir installé votre service sur la machine cible, exécutez simplement votre service à partir de la ligne de commande (comme toute application ordinaire) avec l' -installargument de ligne de commande pour installer et démarrer votre service.

Je pense que j'ai tout couvert, mais si vous trouvez que cela ne fonctionne pas, veuillez me le faire savoir afin que je puisse mettre à jour la réponse.

Matt Davis
la source
12
Notez que cette solution ne nécessite pas l'utilisation d'InstallUtil.exe, vous n'avez donc pas à la fournir dans le cadre de votre programme d'installation.
Matt Davis
2
Quel est l'intérêt des clauses vides "catch {throw;}"? De plus, ce n'est probablement pas une bonne idée de masquer les échecs par "Rollback ()" car cette situation laisse le système dans un état indéfini je suppose (vous avez essayé d'installer un service, échoué quelque part au milieu et ne pouvez pas l'annuler ). Vous devriez au moins "montrer" à l'utilisateur qu'il y a quelque chose de louche - ou est-ce que la fonction Rollback () écrit des messages sur la console?
Christian.K
5
La restauration écrit des données sur la console. En ce qui concerne les blocs catch vides, c'est un problème de débogage. Je peux mettre un point d'arrêt à l'instruction throw pour examiner toutes les exceptions qui peuvent se produire.
Matt Davis le
4
J'obtiens une erreur Erreur: Le type ou le nom de l'espace de noms 'YourServiceType' est introuvable (vous manque une directive using ou une référence d'assemblage?
Yogesh
5
YourServiceTypeest le que ProjectInstallervous avez ajouté au service qui contient ServiceInstalleretServiceProcessInstaller
bansi
6

Visual Studio

Si vous créez un projet d'installation avec VS, vous pouvez créer une action personnalisée qui a appelé une méthode .NET pour démarrer le service. Cependant, il n'est pas vraiment recommandé d'utiliser une action personnalisée gérée dans un MSI. Consultez cette page .

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 ou Wise

Si vous utilisez InstallShield ou Wise, ces applications offrent la possibilité de démarrer le service. Par exemple, avec Wise, vous devez ajouter une action de contrôle de service. Dans cette action, vous spécifiez si vous souhaitez démarrer ou arrêter le service.

Wix

En utilisant Wix, vous devez ajouter le code XML suivant sous le composant de votre service. Pour plus d'informations à ce sujet, vous pouvez consulter cette page .

<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>
Francis B.
la source
5

Vous devez ajouter une action personnalisée à la fin de la séquence «ExecuteImmediate» dans le MSI, en utilisant le nom du composant de l'EXE ou un lot (sc start) comme source. Je ne pense pas que cela puisse être fait avec Visual Studio, vous devrez peut-être utiliser un véritable outil de création MSI pour cela.

Otávio Décio
la source
4

Pour le démarrer juste après l'installation, je génère un fichier batch avec installutil suivi de sc start

Ce n'est pas idéal, mais ça marche ...

Mat
la source
4

Utilisez la classe .NET ServiceController pour le démarrer ou exécutez la commande de ligne de commande pour le démarrer --- "net start servicename". De toute façon fonctionne.

ScottTx
la source
4

Pour ajouter à la réponse de ScottTx, voici le code réel pour démarrer le service si vous le faites à la manière de Microsoft (c'est-à-dire en utilisant un projet d'installation, etc.)

(excusez le code VB.net, mais c'est ce avec quoi je suis coincé)

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

Pour créer le gestionnaire d'événements ci-dessus, accédez au concepteur ProjectInstaller où se trouvent les 2 contrôleurs. Cliquez sur le contrôle ServiceInstaller1. Accédez à la fenêtre des propriétés sous événements et vous y trouverez l'événement AfterInstall.

Remarque: ne placez pas le code ci-dessus sous l'événement AfterInstall pour ServiceProcessInstaller1. Cela ne fonctionnera pas, venant de l'expérience. :)

goku_da_master
la source
Le code VB.net n'est pas mauvais! Pour ceux d'entre nous qui travaillent dans plusieurs langues, c'est bien de ne pas avoir à convertir le code de C!
Steve Reed Sr
Merci, cela m'a aidé à comprendre comment démarrer automatiquement un service.
Charles Owen
0

La solution la plus simple se trouve ici install-windows-service-without-installutil-exe par @ Hoàng Long

@echo OFF
echo Stopping old service version...
net stop "[YOUR SERVICE NAME]"
echo Uninstalling old service version...
sc delete "[YOUR SERVICE NAME]"

echo Installing service...
rem DO NOT remove the space after "binpath="!
sc create "[YOUR SERVICE NAME]" binpath= "[PATH_TO_YOUR_SERVICE_EXE]" start= auto
echo Starting server complete
pause
Robert Green MBA
la source