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.
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?
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é.
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)
Pourquoi ne pas simplement créer un projet d'installation? C'est vraiment facile.
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).
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);
}
}
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).
Topshelf est un projet OSS lancé après la réponse à cette question et qui rend le service Windows beaucoup, BEAUCOUP plus simple.
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.