mercredi 29 janvier 2014

Windows Services - Sample in Visual Studio

Comment correctement administrer et développer vos Services Windows. Ces choses sont assez délicates pour que je prenne ici quelques notes. On a l'impression que c'est simple mais dans la pratique les problèmes se multiplient les problèmes comme le débogage d'un service, son installation, sa désinstallation. Regardons ici ces choses en détails.

Bien sûr il existe de la documentation Microsoft mais il faut beaucoup lire et compiler plusieurs pages avant d'obtenir un résultat. Et surtout cette documentation ne corrige pas les problèmes.

Procédure pas à pas : création d'une application de service Windows
http://msdn.microsoft.com/fr-fr/library/zt39148a(v=vs.110).aspx

Requirements :
Visual Studio 2010
Framework .NET 4.0 ou 2.0

Création du projet Service Windows

La conception d'un Service Windows commence par la création du projet du projet correspondant dans Visual Studio :

Création d'un Service Windows
Notre Service Windows va simplement laisser une trace dans un journal de l'Observateur d'événements qu'il va créer au lancement du service.

La structure de mon projet de Service Windows :

Nouveau projet de Service Windows

Création d'un nouveau journal d'événements

Dans la procédure pas à pas on trouve le code suivant :

if (!System.Diagnostics.EventLog.SourceExists("MySource")) 
{         
System.Diagnostics.EventLog.CreateEventSource(
"MySource","MyNewLog");
}
eventLog1.Source = "MySource";
eventLog1.Log = "MyNewLog";

eventLog1 à été créé grâce au concepteur de vue :

Création de l'objet EventLog grâce au concepteur de vue
Je peux donc ajouter ce code dans Service1.cs, je renomme simplement la Source et le Log :

eventLog1.Source = "WindowsServiceSample";
eventLog1.Log = "WindowsServiceSampleLog";

Commençons à jouer avec le journal des événements, dans Service1.cs j'ajoute le code suivant  : 

protected override void OnStart(string[] args)
{
eventLog1.WriteEntry(DateTime.Now.ToString() + ":Keyboard Sniffer Service Started");
}

protected override void OnStop()
{
eventLog1.WriteEntry(DateTime.Now.ToString() + ":Keyboard Sniffer Service Stopped");
}

Puis je mets un point d'arrêt dans Program.cs :

Insertion d'un point d'arrêt dans le Service Windows
A l'exécution, on obtient :

Cannot start service from the debugger
Là, on se dit que l'on avoir quelques problèmes pour continuer à développer notre Service Windows car tant qu'il n'est pas installer dans le Gestionnaire des Services, on ne peut pas l'exécuter.

Installation du Service Windows

Je prends la Console Visual Studio Command Promt (2010)

InstallUtil dans la Console VS
Je tape les commandes :
>cd \Samples\WindowsServiceSample\WindowsServiceSample\bin\Debug
>installutil WindowsServiceSample.exe

Exécution de la command InstallUtil sur mon Service Windows
Et là, il faut avoir l'oeil et repérer la ligne : No public installers with the RunInstallerAttribute.Yes attribute could be in the ... 
Remove InstallState file because there are no installers.

Bref il faut créer un Installer pour mon service windows.

Création d'un Installeur pour mon Service Windows

C'est tout simple, avec le concepteur de vue de mon composant Service1.cs, je clique bouton droit pour faire "Add Installer" cela ne s'invente pas :

Ajout d'un composant Installer pour mon Service Windows
Un composant ProjectInstaller est automatiquement créé :

Création du composant ProjectInstaller.cs
Remarque : pourquoi le template de Service Windows ne créé pas tout cela dès le départ étant donné que sans le service est inutilisable, les voix de microsoft sont impénétrables.

Je particularise un peu le petit contrôle serviceInstaller1, en ajoutant un Display Name et une Description :

Composant serviceInstaller1
Je retourne dans la Console de Commandes VS et lance à nouveau la commande :
>installutil WindowsServiceSample.exe

InstallUtil Windows Service Sample completed sucessfully
A priori la commande s'est exécutée correctement et mon service doit être installé dans le gestionnaire de mon ordinateur.

Vérifier que le Service Windows est installé correctement

Ouverture de l'outil de Gestion des services : Démarrer->Outils d'administration->Gestion de l'ordinateur
Et là franchement dans la liste de tous les services déjà installé je ne trouve pas mon Service qui devrait s'appeler "Windows Service Sample", j'utilise l’export de la liste :

Exporter la liste ... de tous les services installé
Je désinstalle mon service dans la fenêtre de commandes VS :
>installutil /u WindowsServiceSample.exe

J'exporte à nouveau la liste, je compare les deux liste et là elles sont identiques ! L'installe n'a rien fait, n'a pas installé mon service !

Je me rends compte que je n'avais pas sauver certaines modifications dans le concepteur de vue et donc peut être que la propriété "Display Name" était restée vide ... Je builde je relance la commande d'install et là j'ai une petite boite de dialogue :

Demande de User Login pour l'installation de mon Service Windows
Pas de souci je vais modifier la propriété "Account" de serviceProcessInstaller pour y mettre Local Service :

Modification de l'Account du serviceProcessInstaller1
Je rebuilde et relance la commande d'installe, puis je vérifie que mon service est là :

Windows Service Sample est bien là !
Enfin mon service est présent dans la liste des Services Installé, le fichier journal WindowsServiceSampleLog a été créé.

Mon service est à démarrage manuel, je clique donc sur démarrer, puis stopper puis redémarrer, je vais visiter le fichier journal, les logs sont biens là :

Démarrage du Service Windows écritures dans le fichier journal
La prochaine fois nous verrons comment attacher le débogueur pour déboguer notre service windows et nous verrons encore bien d'autres problèmes.

Download Source Code

Have fun !