web-dev-qa-db-fra.com

Windows Service à exécuter en permanence

J'ai créé un service Windows appelé ProxyMonitor et je suis actuellement au stade où le service est installé et désinstallé comme je le souhaite.

Donc, j'exécute l'application comme suit:

C:\\Windows\\Vendor\\ProxyMonitor.exe /install

C'est assez explicite, puis je suis arrivé à services.msc et je lance le service, mais lorsque je le fais, je reçois le message suivant:

Le service de surveillance proxy sur l'ordinateur local a démarré puis s'est arrêté. Certains services s'arrêtent automatiquement s'il n'y a pas de travail à faire. Par exemple, les services de journalisation et d'alertes de performance

Mon code ressemble à ceci:

public static Main(string[] Args)
{
    if (System.Environment.UserInteractive)
    {
        /*
            * Here I have my install logic
        */
    }
    else
    {
        ServiceBase.Run(new ProxyMonitor());
    }
}

Et puis dans la classe ProxyMonitor, j'ai:

public ProxyMonitor()
{
}

protected override void OnStart(string[] args)
{
    base.OnStart(args);
    ProxyEventLog.WriteEntry("ProxyMonitor Started");

    running = true;
    while (running)
    {
        //Execution Loop
    }
}

et onStop() Je viens de changer la variable running en false;

Que devrais-je faire pour rendre le service actif en permanence, tout comme je devrais surveiller le réseau dont j'ai besoin pour suivre les modifications, etc.


Mise à jour: 1

protected override void OnStart(string[] args)
{
     base.OnStart(args);
     ProxyEventLog.WriteEntry("ProxyMonitor Started");

     Thread = new Thread(ThreadWorker);
     Thread.Start();
 }

Dans la ThreadWorker j'ai ProxyEventLogger.WriteEntry("Main thread entered") qui ne se fait pas virer.

50
RobertPitt

Le rappel OnStart() doit être renvoyé à temps, vous voudrez donc lancer un fil où tout votre travail sera effectué. Je recommanderais d'ajouter les champs suivants à votre classe:

using System.Threading;
private ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
private Thread _thread;

Le champ _thread contiendra une référence à l'objet System.Threading.Thread que vous avez créé dans le rappel OnStart(). Le champ _shutdownEvent contient une construction d'événement de niveau système qui sera utilisée pour indiquer au thread de cesser de s'exécuter à la fermeture du service.

Dans le callback OnStart(), créez et démarrez votre thread.

protected override void OnStart(string[] args)
{
     _thread = new Thread(WorkerThreadFunc);
     _thread.Name = "My Worker Thread";
     _thread.IsBackground = true;
     _thread.Start();
}

Vous avez besoin d’une fonction nommée WorkerThreadFunc pour que cela fonctionne. Il doit correspondre à la signature System.Threading.ThreadStart delegate.

private void WorkerThreadFunc()
{
}

Si vous ne mettez rien dans cette fonction, le thread démarrera puis s’arrêtera immédiatement. Vous devez donc y insérer une logique qui le maintient en vie pendant que vous travaillez. C'est ici que le _shutdownEvent est utile.

private void WorkerThreadFunc()
{
    while (!_shutdownEvent.WaitOne(0)) {
        // Replace the Sleep() call with the work you need to do
        Thread.Sleep(1000);
    }
}

La boucle while vérifie la ManualResetEvent pour voir si elle est "définie" ou non. Puisque nous avons initialisé l'objet avec false ci-dessus, cette vérification renvoie false. Dans la boucle, nous dormons pendant 1 seconde. Vous voudrez remplacer ceci par le travail que vous devez faire - surveiller les paramètres de proxy, etc.

Enfin, dans le callback OnStop() de votre service Windows, vous souhaitez signaler au thread de s’interrompre. C'est facile en utilisant le _shutdownEvent.

protected override void OnStop()
{
     _shutdownEvent.Set();
     if (!_thread.Join(3000)) { // give the thread 3 seconds to stop
         _thread.Abort();
     }
} 

J'espère que cela t'aides.

135
Matt Davis

Vous devez quitter votre gestionnaire OnStart pour que le contrôleur de service réalise que votre service a réellement démarré. Pour que tout fonctionne comme vous le souhaitez, vous pouvez démarrer une minuterie qui se déclenche à intervalles réguliers et qui se déclenche une fois à l’autre.

Modifier:

Essayez de placer un System.Diagnostics.Debugger.Launch () dans votre OnStart pour voir ce qui se passe (et mettez un point d'arrêt dans ThreadWorker). Je recommanderais de placer ceci dans #if DEBUG pour m'assurer qu'il ne soit pas déployé.

Je viens aussi de réaliser que vous ne donnez pas à votre Thread un nom:

 Thread myThread = new Thread(ThreadWorker);
 myThread.Start();
6
Mark Avenius

Certainement pas l'ajout d'une boucle while dans la méthode OnStart. Cela indiquera au système d'exploitation que le service n'a pas démarré car il n'a pas pu sortir en toute sécurité de la méthode OnStart. Je crée généralement une Timer qui est activée dans la méthode OnStart. Ensuite, dans la méthode Ticks, j'appelle la méthode nécessaire pour que l'application s'exécute.

Vous pouvez également effectuer les opérations suivantes:

// The main entry point for the process 
static void Main() 
{ 
    System.ServiceProcess.ServiceBase[] ServicesToRun; 
    ServicesToRun = new System.ServiceProcess.ServiceBase[] { new WinService1() }; 
    System.ServiceProcess.ServiceBase.Run(ServicesToRun); 
} 

Pour plus d'informations sur les services Windows, vous pouvez obtenir un exemple squelette ici .

2
Neil Knight

Exemple de code présenté à l'aide d'une application console. espérons que cela aidera ..  

 class Program
{
    private static CancellationTokenSource _cancellationTokenSource;
    private static ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
    private static Thread _serviceStartThread;
    private static Thread _serviceStopThread;

    private static int workcounter = 0;
    static void Main(string[] args)
    {

        _cancellationTokenSource = new CancellationTokenSource();
        _serviceStartThread = new Thread(DoWork);
        _serviceStopThread = new Thread(ScheduledStop);
        StartService();
        StopService();
    }

    private static void StartService()
    {
        _serviceStartThread.Start();

    }

    private static void StopService()
    {
        _serviceStopThread.Start();
    }


    /// <summary>
    /// Triggers a cancellation event for stopping the service in a timely fashion.
    /// </summary>
    private static void ScheduledStop()
    {
        while (!_shutdownEvent.WaitOne(0))
        {
            if (workcounter == 10)
            {
                _cancellationTokenSource.Cancel();
            }
        }
    }

    /// <summary>
    /// Represents a long running Task with cancellation option
    /// </summary>
    private static void DoWork()
    {

        while (!_shutdownEvent.WaitOne(0))
        {
            if(!_cancellationTokenSource.Token.IsCancellationRequested)
            {
                workcounter += 1;
                Console.Write(Environment.NewLine);
                Console.Write("Running...counter: " + workcounter.ToString());
                Thread.Sleep(1000);//Not needed, just for demo..
            }
            else
            {
                Console.Write(Environment.NewLine);
                Console.Write("Recieved cancellation token,shutting down in 5 seconds.. counter: " + workcounter.ToString());
                _shutdownEvent.Set();
                Thread.Sleep(5000);//Not needed, just for demo..
            }

        }
    }
}
2

Pourquoi ne créez-vous pas un nouveau projet dans votre solution du type Service Windows? Ceci configure toutes les structures que vous devez implémenter, y compris les gestionnaires pour les événements de démarrage/arrêt du service.

0
Gabriel Magana