Dot.Blog

C#, XAML, Xamarin, UWP/Android/iOS

Soignez votre service !

butler-159811_640[new:30/04/2015]Les services sous Windows sont d’une grande utilité et sont bien plus élégants que tous ces exécutables qu’on place dans le démarrage de l’OS pour jouer en fait le même rôle. Mais le debug d’un service est si pénible… une vraie plaie ! Ou pas… Regardons comment en faire un vrai bonheur !

Les services toujours d’actualité

Les services Windows ont toujours été utiles. Ils existent depuis des temps immémoriaux. C’est un sujet sans âge. Mais il s’agit d’un type d’application aussi important qu’un exe traditionnel, sauf qu’on en parle beaucoup moins.

Potentiellement un service peut faire les mêmes choses qu’un exe, il est donc tentant de faire un simple exécutable facile à déboguer et puis de le placer dans le démarrage de Windows histoire qu’il se lance tout seul… Mais ce n’est pas un service. Il ne peut prétendre exactement aux mêmes tâches et aux mêmes API, à la même sécurité, et tout plein de choses qui font que les services sont des services.

De plus se “trainer” une gestion d’UI, de Windows Forms ou WPF, dans une application sans interaction c’est tout de même un peu “cracra”, les octets ne se comptent plus comme avant certes, mais le principe est sale, c’est du travail mal fait.

Certes.

Mais développer un service Windows est une plaie. C’est simple, ça oui, mais c’est impossible à déboguer sous VS et du coup la mise au point devient tellement pénible que par reflexe on évite de créer des services, on se débrouille autrement. Et la boucle est bouclée revenez deux paragraphes plus haut et relisez vous aurez un remake d’ “un jour sans fin” !

Heureusement vous sortirez vite de cette boucle infinie et vous lirez la présente ligne car vous êtes un humain, pas un PC ! Et c’est tant mieux car si vous ne connaissez pas l’astuce je vais vous faire voir comment transformer cette plaie en vrai bonheur, à tel point que vous allez avoir envie dans dix minutes de développer tout sous forme de services Windows !

Faire d’un Service un Bonheur ( = qui peut se déboguer sous VS)

Nous supposerons ici que vous avez déjà un service Windows ou que vous savez utilisez VS pour en créer le squelette (ce n’est pas bien compliqué !).

Maintenant que nous disposons de ce service (peu importe ce que fait la partie utile), voici comment le modifier pour qu’il puisse à la fois tourner en tant que service et être débogué sous VS, voire être lancé séparément comme un exe standard.

Etape 1 : mode console

Par défaut il y a toutes les chances que votre service soit compilé en tant qu’application Windows. Pour nous débarrasser des UI inutiles ici nous allons en faire une application console.

Rien de plus simple : dans les propriété du projet il suffit de changer le “output type” (type de sortie) en console.

C’est pas bien sorcier…

Etape 2 : modifier le Main()

La grosse astuce se trouve là, en modifiant la méthode Main() du programme (program.cs) nous allons détecter si notre code tourne dans un environnement interactif ou non. En gros je ne connais que les services qui ne sont pas interactifs et ce test fonctionne donc à merveille.

De fait le mode de fonctionnement ne sera pas seulement versatile (service vrai ou console) mais il s’adaptera tout seul à la circonstance ! Lancé sous VS il saura s’exécuter en mode console qu’on peut déboguer facilement, lancé par l’OS il saura s’exécuter en mode service Windows…

Voici le code de la méthode Main() modifié :

static void Main()
{
    ServiceBase[] servicesToRun;
    servicesToRun = new ServiceBase[] 
    {
        new MyService()
    };
    if (Environment.UserInteractive)
    {
        RunInteractive(servicesToRun);
    }
    else
    {
        ServiceBase.Run(servicesToRun);
    }
}

 

Toute la ruse se trouve donc dans la détection automatique du mode interactif et dans le “if” qui soit fait un Run classique pour un service Windows, soit lance le code en mode console via la méthode “RunInteractive”.

Certes cette dernière n’existe pas… Mais nous allons l’écrire :

static void RunInteractive(ServiceBase[] servicesToRun)
{
    Console.WriteLine("Services running in interactive mode.");
    Console.WriteLine();
 
    MethodInfo onStartMethod = typeof(ServiceBase).GetMethod("OnStart", 
        BindingFlags.Instance | BindingFlags.NonPublic);
    foreach (ServiceBase service in servicesToRun)
    {
        Console.Write("Starting {0}...", service.ServiceName);
        onStartMethod.Invoke(service, new object[] { new string[] { } });
        Console.Write("Started");
    }
 
    Console.WriteLine();
    Console.WriteLine();
    Console.WriteLine(
        "Press any key to stop the services and end the process...");
    Console.ReadKey();
    Console.WriteLine();
 
    MethodInfo onStopMethod = typeof(ServiceBase).GetMethod("OnStop", 
        BindingFlags.Instance | BindingFlags.NonPublic);
    foreach (ServiceBase service in servicesToRun)
    {
        Console.Write("Stopping {0}...", service.ServiceName);
        onStopMethod.Invoke(service, null);
        Console.WriteLine("Stopped");
    }
 
    Console.WriteLine("All services stopped.");
    // Keep the console alive for a second to allow the user to see the message.
    Thread.Sleep(1500);
}

 

C’est fini !

Désormais le service sera exécuté comme tel ou bien comme un exécutable classique ce qui en autorise la mise au point sous Visual Studio avec débogue et tout ce qu’il faut pour travailler vite et bien…

J’avais développé il y a longtemps une version qui utilisait une fenêtre Windows Forms ce qui permettait d’afficher des infos sur le service, envoyer des messages sur son fonctionnement etc. Mais la console c’est plus simple et plus direct. A vous de compliquer la solution ici proposée si cela vous dit. Cela évite en plus de trimbaler dans le service toute la librairie qui gère l’UI. Cette variante en mode console m’a été inspirée par un billet de Anders Abel alors que je revisitais tout cela pour voir si on avait trouvé mieux depuis ma combine en Windows Forms. On n’a pas trouvé vraiment mieux, mais c’est plus court et encore plus sobre alors c’est ce code de Anders que vous montre ici, c’est une bonne base pour ajouter des choses selon vos besoins.

Conclusion

Les services Windows c’est génial, ça se lance tout seul, ça tourne dans son coin et ça peut faire plein de trucs utiles. Mais c’est une horreur à déboguer.

En utilisant l’astuce présentée ici je suis convaincu que vous changerez d’opinion et que développer des services ne vous semblera plus un chemin de croix.

Et Stay Tuned !

blog comments powered by Disqus