web-dev-qa-db-fra.com

Installer le service Windows sans InstallUtil.exe

J'essaie de déployer un service Windows mais je ne sais pas trop comment le faire correctement. Je l'ai construite comme une application de console pour commencer, je l'ai maintenant transformée en projet de service Windows et je viens d'appeler ma classe à partir de la méthode OnStart du service.

Je dois maintenant l'installer sur un serveur sur lequel Visual Studio n'est pas installé. Si je comprends bien, cela signifie que je ne peux pas utiliser InstallUtil.exe et que je dois plutôt créer une classe d'installation. Est-ce correct?

J'ai jeté un coup d'oeil à une question précédente, Installez un service Windows .NET sans InstallUtil.exe , mais je veux simplement m'assurer que je l'ai bien compris.

Si je crée la classe dans laquelle la réponse acceptée renvoie à la question, quelle est l'étape suivante? Téléchargez MyService.exe et MyService.exe.config sur le serveur, double-cliquez sur le fichier exe et Bob est mon oncle?

Le service ne sera jamais installé que sur un serveur.

36
annelie

L'outil InstallUtil.exe encapsule simplement quelques appels de réflexion sur le ou les composants du programme d'installation de votre service. En tant que tel, il ne fait vraiment pas grand chose mais exerce les fonctionnalités fournies par ces composants d'installation. La solution de Marc Gravell fournit simplement un moyen de le faire à partir de la ligne de commande afin que vous n'ayez plus à compter sur InstallUtil.exe sur la machine cible.

Voici mon étape par étape basée sur la solution de Marc Gravell.

Comment faire en sorte qu'un service Windows .NET démarre juste après l'installation?

18
Matt Davis

Je sais que la question est très ancienne, mais il vaut mieux la mettre à jour avec de nouvelles informations.

Vous pouvez installer le service en utilisant sc command:

InstallService.bat:

@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

Avec SC, vous pouvez également faire beaucoup plus de choses: désinstaller l'ancien service (si vous l'aviez déjà installé auparavant), vérifier si un service portant le même nom existe ... même configurer votre service pour un démarrage automatique.

Une des nombreuses références: créer un service avec sc.exe; comment passer en paramètres de contexte

J'ai fait par les deux cette façon & InstallUtil. Personnellement, j’estime que l’utilisation de SC est plus propre et plus bénéfique pour la santé.

42
Hoàng Long

Vous pouvez toujours utiliser installutil sans visual studio, il est inclus dans le framework .net

Sur votre serveur, ouvrez une invite de commande en tant qu'administrateur puis:

CD C:\Windows\Microsoft.NET\Framework\v4.0.version (insert your version)

installutil "C:\Program Files\YourWindowsService\YourWindowsService.exe" (insert your service name/location)

Pour désinstaller:

installutil /u "C:\Program Files\YourWindowsService\YourWindowsService.exe" (insert your service name/location)
30

Pourquoi ne pas simplement créer un projet d'installation? C'est vraiment facile. 

  1. Ajoutez un programme d'installation de service au service (vous le faites sur la surface "de conception" de service apparemment inutile) 
  2. Créez un projet d'installation et ajoutez la sortie du service au dossier de l'application d'installation.
  3. Plus important encore, ajoutez la sortie du projet de service à toutes les actions personnalisées.

Voilà, et vous avez terminé.

Voir ici pour plus d'informations: http://www.codeproject.com/KB/dotnet/simplewindowsservice.aspx

Il existe également un moyen de demander à l'utilisateur des informations d'identification (ou de fournir les vôtres). 

5
Doobi

Il s'agit d'une classe de service de base (sous-classe ServiceBase) pouvant être sous-classée pour créer un service Windows pouvant être facilement installé à partir de la ligne de commande, sans installutil.exe. Cette solution est dérivée de Comment faire en sorte qu'un service Windows .NET démarre juste après l'installation? , ajout de code pour obtenir le type de service en utilisant le StackFrame appelant 

public abstract class InstallableServiceBase:ServiceBase
{

    /// <summary>
    /// returns Type of the calling service (subclass of InstallableServiceBase)
    /// </summary>
    /// <returns></returns>
    protected static Type getMyType()
    {
        Type t = typeof(InstallableServiceBase);
        MethodBase ret = MethodBase.GetCurrentMethod();
        Type retType = null;
        try
        {
            StackFrame[] frames = new StackTrace().GetFrames();
            foreach (StackFrame x in frames)
            {
                ret = x.GetMethod();

                Type t1 = ret.DeclaringType;

                if (t1 != null && !t1.Equals(t) &&   !t1.IsSubclassOf(t))
                {


                    break;
                }
                retType = t1;
            }
        }
        catch
        {

        }
        return retType;
    }
    /// <summary>
    /// returns AssemblyInstaller for the calling service (subclass of InstallableServiceBase)
    /// </summary>
    /// <returns></returns>
    protected static AssemblyInstaller GetInstaller()
    {
        Type t = getMyType();
        AssemblyInstaller installer = new AssemblyInstaller(
            t.Assembly, null);
        installer.UseNewContext = true;
        return installer;
    }

    private bool IsInstalled()
    {
        using (ServiceController controller =
            new ServiceController(this.ServiceName))
        {
            try
            {
                ServiceControllerStatus status = controller.Status;
            }
            catch
            {
                return false;
            }
            return true;
        }
    }

    private bool IsRunning()
    {
        using (ServiceController controller =
            new ServiceController(this.ServiceName))
        {
            if (!this.IsInstalled()) return false;
            return (controller.Status == ServiceControllerStatus.Running);
        }
    }
    /// <summary>
    /// protected method to be called by a public method within the real service
    /// ie: in the real service
    ///    new internal  void InstallService()
    ///    {
    ///        base.InstallService();
    ///    }
    /// </summary>
    protected void InstallService()
    {
        if (this.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;
        }
    }
    /// <summary>
    /// protected method to be called by a public method within the real service
    /// ie: in the real service
    ///    new internal  void UninstallService()
    ///    {
    ///        base.UninstallService();
    ///    }
    /// </summary>
    protected void UninstallService()
    {
        if (!this.IsInstalled()) return;

        if (this.IsRunning()) {
            this.StopService();
        }
        try
        {
            using (AssemblyInstaller installer = GetInstaller())
            {
                IDictionary state = new Hashtable();
                try
                {
                    installer.Uninstall(state);
                }
                catch
                {
                    throw;
                }
            }
        }
        catch
        {
            throw;
        }
    }

    private void StartService()
    {
        if (!this.IsInstalled()) return;

        using (ServiceController controller =
            new ServiceController(this.ServiceName))
        {
            try
            {
                if (controller.Status != ServiceControllerStatus.Running)
                {
                    controller.Start();
                    controller.WaitForStatus(ServiceControllerStatus.Running,
                        TimeSpan.FromSeconds(10));
                }
            }
            catch
            {
                throw;
            }
        }
    }

    private void StopService()
    {
        if (!this.IsInstalled()) return;
        using (ServiceController controller =
            new ServiceController(this.ServiceName))
        {
            try
            {
                if (controller.Status != ServiceControllerStatus.Stopped)
                {
                    controller.Stop();
                    controller.WaitForStatus(ServiceControllerStatus.Stopped,
                         TimeSpan.FromSeconds(10));
                }
            }
            catch
            {
                throw;
            }
        }
    }
}

Tout ce que vous avez à faire est d'implémenter deux méthodes publiques/internes dans votre service réel:

    new internal  void InstallService()
    {
        base.InstallService();
    }
    new internal void UninstallService()
    {
        base.UninstallService();
    }

puis appelez-les lorsque vous souhaitez installer le service:

    static void Main(string[] args)
    {
        if (Environment.UserInteractive)
        {
            MyService s1 = new MyService();
            if (args.Length == 1)
            {
                switch (args[0])
                {
                    case "-install":
                        s1.InstallService();

                        break;
                    case "-uninstall":

                        s1.UninstallService();
                        break;
                    default:
                        throw new NotImplementedException();
                }
            }


        }
        else {
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[] 
            { 
                new MyService() 
            };
            ServiceBase.Run(MyService);            
        }

    }
2
Luca Manzo

Ne double-cliquez pas, vous l'exécutez avec les paramètres de ligne de commande appropriés. Tapez quelque chose comme MyService -i puis MyService -u pour le désinstaller.

Vous pouvez également utiliser sc.exe pour l'installer et le désinstaller (ou copier le long de InstallUtil.exe).

0
Hans Olsson

Topshelf est un projet OSS lancé après la réponse à cette question et qui rend le service Windows beaucoup, BEAUCOUP plus simple.

http://topshelf-project.com/

0
Doobi

Ce problème est dû à la sécurité, il vaut mieux ouvrir l'invite de commande du développeur pour VS 2012 dans RUN AS ADMINISTRATOR et installer votre service, cela corrigera sûrement votre problème.

0
Ankur Kumar