ServiceBase, classe

ServiceBase, classe

Fournit une classe de base pour un service qui fera partie d'une application de service. ServiceBase doit être dérivé lors de la création d'une classe de service.

Espace de noms : System.ServiceProcess
Assembly : System.ServiceProcess (dans system.serviceprocess.dll)

public class ServiceBase : Component
public class ServiceBase extends Component
public class ServiceBase extends Component

Dérivez votre classe de service de ServiceBase lorsque vous la définissez dans une application de service. Tout service utile substitue les méthodes OnStart et OnStop. Pour une fonctionnalité plus riche, vous pouvez substituer OnPause et OnContinue par un comportement spécifique en réaction aux modifications d'état du service.

Un service est un exécutable qui tourne pendant longtemps, qui ne prend pas en charge d'interface utilisateur et qui peut ne pas s'exécuter sous le compte de l'utilisateur ayant ouvert une session. Le service peut s'exécuter quand aucun utilisateur n'est en session sur l'ordinateur.

Par défaut, les services s'exécutent sous le compte système, lequel est différent du compte d'administrateur. Vous ne pouvez pas modifier les droits associés au compte système. Vous avez également la possibilité d'utiliser ServiceProcessInstaller pour spécifier un compte d'utilisateur sous lequel le service s'exécutera.

Un exécutable peut contenir plus d'un service à condition de comprendre un ServiceInstaller distinct pour chaque service. L'instance de ServiceInstaller inscrit le service dans le système. Le programme d'installation associe aussi chaque service à un journal des événements que vous pouvez utiliser pour enregistrer les commandes du service. La fonction main() de l'exécutable définit les services qui doivent s'exécuter. Le répertoire de travail actif du service est le répertoire système et non le répertoire où se trouve l'exécutable.

Lorsque vous démarrez un service, le système trouve l'exécutable et exécute la méthode OnStart pour ce service qui se trouve dans l'exécutable. Toutefois, il convient de faire la distinction entre l'exécution du service et celle de l'exécutable. L'exécutable se contente de charger le service. Vous accédez au service lui-même (pour le démarrer et l'arrêter notamment) par le biais du Gestionnaire de contrôle des services.

L'exécutable appelle le constructeur de la classe dérivée ServiceBase lorsque vous appelez pour la première fois Start sur le service. La méthode de gestion de commande OnStart est appelée immédiatement après l'exécution du constructeur. Le constructeur ne s'exécute plus après le chargement initial du service ; il est donc nécessaire de séparer le traitement effectué par le constructeur de celui effectué par OnStart. Toutes les ressources qui peuvent être libérées par OnStop doivent être créées dans OnStart. Le fait de créer les ressources dans le constructeur empêche qu'elles ne soient créées correctement dans le cas où le service serait redémarré après la libération de ces ressources par OnStop.

Le Gestionnaire de contrôle des services (SCM, Service Control Manager) permet l'interaction avec le service. Vous pouvez utiliser SCM pour passer au service des commandes Démarrer, Arrêter, Suspendre, Continuer ou des commandes personnalisées. Le Gestionnaire de contrôle des services utilise les valeurs de CanStop et CanPauseAndContinue pour déterminer si le service accepte les commandes Arrêter, Suspendre et Continuer. Les commandes Arrêter, Suspendre et Continuer ne sont activées dans les menus contextuels de SCM que si la propriété correspondante CanStop ou CanPauseAndContinue a la valeur true dans la classe du service. Si elle est activée, la commande est passée au service et la méthode OnStop, OnPause ou OnContinue est appelée. Si CanStop, CanShutdown ou CanPauseAndContinue a la valeur false, la méthode de gestion de commande correspondante (par exemple, OnStop) n'est pas traitée, même si vous avez implémenté cette méthode.

Vous pouvez utiliser la classe ServiceController pour accomplir par programme ce que fait le Gestionnaire de contrôle des services à l'aide d'une interface utilisateur. Il est possible d'automatiser les tâches disponibles dans la console. Si CanStop, CanShutdown ou CanPauseAndContinue a la valeur true et que vous n'avez pas implémenté la méthode de gestion de commande correspondante (par exemple, OnStop), le système lève une exception et ignore la commande.

Il n'est pas nécessaire d'implémenter OnStart, OnStop ou toute autre méthode de ServiceBase. Toutefois, comme le comportement du service est décrit dans OnStart, il convient au minimum de substituer ce membre. Vous devez définir le nom du service dans la fonction main() de l'exécutable. Le nom de service que vous définissez dans main() doit correspondre exactement à la propriété ServiceName du programme d'installation du service.

Vous pouvez utiliser InstallUtil.exe pour installer des services sur votre système.

RemarqueRemarque

Vous pouvez spécifier un journal différent du journal des événements de l'application pour recevoir la notification des appels du service ; toutefois, aucune des propriétés AutoLog et EventLog ne peut écrire dans un journal personnalisé. Affectez à AutoLog la valeur false si vous ne souhaitez pas utiliser l'enregistrement automatique dans le journal.

L'exemple suivant dérive une implémentation de service simple de la classe ServiceBase. Ce service gère diverses commandes de service, notamment Stop, Start, Pause, Continue et les commandes personnalisées.

// Turn on logging to the event log.
#define LOGEVENTS

using System;
using System.IO;
using System.Threading;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using Microsoft.Win32;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace ServiceSample
{
    // Define custom commands for the SimpleService.
    public enum SimpleServiceCustomCommands { StopWorker = 128, RestartWorker, CheckWorker };
    [StructLayout(LayoutKind.Sequential)]
    public struct SERVICE_STATUS
    {
        public int serviceType;
        public int currentState;
        public int controlsAccepted;
        public int win32ExitCode;
        public int serviceSpecificExitCode;
        public int checkPoint;
        public int waitHint;
    }

    public enum State
    {
        SERVICE_STOPPED = 0x00000001,
        SERVICE_START_PENDING = 0x00000002,
        SERVICE_STOP_PENDING = 0x00000003,
        SERVICE_RUNNING = 0x00000004,
        SERVICE_CONTINUE_PENDING = 0x00000005,
        SERVICE_PAUSE_PENDING = 0x00000006,
        SERVICE_PAUSED = 0x00000007,
    }

    // Define a simple service implementation.
    public class SimpleService : System.ServiceProcess.ServiceBase
    {
        private static int userCount = 0;
        private static ManualResetEvent pause = new ManualResetEvent(false);

        [DllImport("ADVAPI32.DLL", EntryPoint = "SetServiceStatus")]
        public static extern bool SetServiceStatus(
                        IntPtr hServiceStatus,
                        SERVICE_STATUS lpServiceStatus
                        );
        private SERVICE_STATUS myServiceStatus;

        private Thread workerThread = null;

        public SimpleService()
        {
            CanPauseAndContinue = true;
            CanHandleSessionChangeEvent = true;
            ServiceName = "SimpleService";
        }

        static void Main()
        {
#if LOGEVENTS
            EventLog.WriteEntry("SimpleService.Main", DateTime.Now.ToLongTimeString() +
                " - Service main method starting...");
#endif

            // Load the service into memory.
            System.ServiceProcess.ServiceBase.Run(new SimpleService());

#if LOGEVENTS
            EventLog.WriteEntry("SimpleService.Main", DateTime.Now.ToLongTimeString() +
                " - Service main method exiting...");
#endif

        }

        private void InitializeComponent()
        {
            // Initialize the operating properties for the service.
            this.CanPauseAndContinue = true;
            this.CanShutdown = true;
            this.CanHandleSessionChangeEvent = true;
            this.ServiceName = "SimpleService";
        }

        // Start the service.
        protected override void OnStart(string[] args)
        {
            IntPtr handle = this.ServiceHandle;
            myServiceStatus.currentState = (int)State.SERVICE_START_PENDING;
            SetServiceStatus(handle, myServiceStatus);

            // Start a separate thread that does the actual work.

            if ((workerThread == null) ||
                ((workerThread.ThreadState &
                 (System.Threading.ThreadState.Unstarted | System.Threading.ThreadState.Stopped)) != 0))
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnStart", DateTime.Now.ToLongTimeString() +
                    " - Starting the service worker thread.");
#endif

                workerThread = new Thread(new ThreadStart(ServiceWorkerMethod));
                workerThread.Start();
            }
            if (workerThread != null)
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnStart", DateTime.Now.ToLongTimeString() +
                    " - Worker thread state = " +
                    workerThread.ThreadState.ToString());
#endif
            }
            myServiceStatus.currentState = (int)State.SERVICE_RUNNING;
            SetServiceStatus(handle, myServiceStatus);

        }

        // Stop this service.
        protected override void OnStop()
        {
            // New in .NET Framework version 2.0.
            this.RequestAdditionalTime(4000);
            // Signal the worker thread to exit.
            if ((workerThread != null) && (workerThread.IsAlive))
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnStop", DateTime.Now.ToLongTimeString() +
                    " - Stopping the service worker thread.");
#endif
                pause.Reset();
                Thread.Sleep(5000);
                workerThread.Abort();

            }
            if (workerThread != null)
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnStop", DateTime.Now.ToLongTimeString() +
                    " - OnStop Worker thread state = " +
                    workerThread.ThreadState.ToString());
#endif
            }
            // Indicate a successful exit.
            this.ExitCode = 0;
        }

        // Pause the service.
        protected override void OnPause()
        {
            // Pause the worker thread.
            if ((workerThread != null) &&
                (workerThread.IsAlive) &&
                ((workerThread.ThreadState &
                 (System.Threading.ThreadState.Suspended | System.Threading.ThreadState.SuspendRequested)) == 0))
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnPause", DateTime.Now.ToLongTimeString() +
                    " - Pausing the service worker thread.");
#endif

                pause.Reset();
                Thread.Sleep(5000);
            }

            if (workerThread != null)
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnPause", DateTime.Now.ToLongTimeString() +
                    " OnPause - Worker thread state = " +
                    workerThread.ThreadState.ToString());
#endif
            }
        }

        // Continue a paused service.
        protected override void OnContinue()
        {

            // Signal the worker thread to continue.
            if ((workerThread != null) &&
                ((workerThread.ThreadState &
                 (System.Threading.ThreadState.Suspended | System.Threading.ThreadState.SuspendRequested)) != 0))
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnContinue", DateTime.Now.ToLongTimeString() +
                    " - Resuming the service worker thread.");

#endif
                pause.Set();
            }
            if (workerThread != null)
            {
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.OnContinue", DateTime.Now.ToLongTimeString() +
                    " OnContinue - Worker thread state = " +
                    workerThread.ThreadState.ToString());
#endif
            }
        }

        // Handle a custom command.
        protected override void OnCustomCommand(int command)
        {
#if LOGEVENTS
            EventLog.WriteEntry("SimpleService.OnCustomCommand", DateTime.Now.ToLongTimeString() +
                " - Custom command received: " +
                command.ToString());
#endif

            // If the custom command is recognized,
            // signal the worker thread appropriately.

            switch (command)
            {
                case (int)SimpleServiceCustomCommands.StopWorker:
                    // Signal the worker thread to terminate.
                    // For this custom command, the main service
                    // continues to run without a worker thread.
                    OnStop();
                    break;

                case (int)SimpleServiceCustomCommands.RestartWorker:

                    // Restart the worker thread if necessary.
                    OnStart(null);
                    break;

                case (int)SimpleServiceCustomCommands.CheckWorker:
#if LOGEVENTS
                    // Log the current worker thread state.
                    EventLog.WriteEntry("SimpleService.OnCustomCommand", DateTime.Now.ToLongTimeString() +
                        " OnCustomCommand - Worker thread state = " +
                        workerThread.ThreadState.ToString());
#endif

                    break;

                default:
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnCustomCommand",
                        DateTime.Now.ToLongTimeString());
#endif
                    break;
            }
        }
        // Handle a session change notice
        protected override void OnSessionChange(SessionChangeDescription changeDescription)
        {
#if LOGEVENTS
            EventLog.WriteEntry("SimpleService.OnSessionChange", DateTime.Now.ToLongTimeString() +
                " - Session change notice received: " +
                changeDescription.Reason.ToString() + "  Session ID: " + 
                changeDescription.SessionId.ToString());
#endif

            switch (changeDescription.Reason)
            {
                case SessionChangeReason.SessionLogon:
                    userCount += 1;
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange", 
                        DateTime.Now.ToLongTimeString() +
                        " SessionLogon, total users: " +
                        userCount.ToString());
#endif
                    break;

                case SessionChangeReason.SessionLogoff:

                    userCount -= 1;
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange", 
                        DateTime.Now.ToLongTimeString() +
                        " SessionLogoff, total users: " +
                        userCount.ToString());
#endif
                    break;
                case SessionChangeReason.RemoteConnect:
                    userCount += 1;
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange", 
                        DateTime.Now.ToLongTimeString() +
                        " RemoteConnect, total users: " +
                        userCount.ToString());
#endif
                    break;

                case SessionChangeReason.RemoteDisconnect:

                    userCount -= 1;
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange", 
                        DateTime.Now.ToLongTimeString() +
                        " RemoteDisconnect, total users: " +
                        userCount.ToString());
#endif
                    break;
                case SessionChangeReason.SessionLock:
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange", 
                        DateTime.Now.ToLongTimeString() + 
                        " SessionLock");
#endif
                    break;

                case SessionChangeReason.SessionUnlock:
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.OnSessionChange", 
                        DateTime.Now.ToLongTimeString() + 
                        " SessionUnlock");
#endif
                    break;

                default:

                    break;
            }
        }
        // Define a simple method that runs as the worker thread for 
        // the service.  
        public void ServiceWorkerMethod()
        {
#if LOGEVENTS
            EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() +
                " - Starting the service worker thread.");
#endif

            try
            {
                do
                {
                    // Simulate 4 seconds of work.
                    Thread.Sleep(4000);
                    // Block if the service is paused or is shutting down.
                    pause.WaitOne();
#if LOGEVENTS
                    EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() +
                        " - heartbeat cycle.");
#endif
                }
                while (true);
            }
            catch (ThreadAbortException)
            {
                // Another thread has signalled that this worker
                // thread must terminate.  Typically, this occurs when
                // the main service thread receives a service stop 
                // command.

                // Write a trace line indicating that the worker thread
                // is exiting.  Notice that this simple thread does
                // not have any local objects or data to clean up.
#if LOGEVENTS
                EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() +
                    " - Thread abort signaled.");
#endif
            }
#if LOGEVENTS

            EventLog.WriteEntry("SimpleService.WorkerThread", DateTime.Now.ToLongTimeString() +
                " - Exiting the service worker thread.");
#endif

        }
    }
}

System.Object
   System.MarshalByRefObject
     System.ComponentModel.Component
      System.ServiceProcess.ServiceBase

Les membres statiques publics (Shared en Visual Basic) de ce type sont thread-safe. Il n'est pas garanti que les membres d'instance soient thread-safe.

Windows 98, Windows 2000 SP4, Windows Server 2003, Windows XP Édition Media Center, Windows XP Professionnel Édition x64, Windows XP SP2, Windows XP Starter Edition

Le .NET Framework ne prend pas en charge toutes les versions de chaque plate-forme. Pour obtenir la liste des versions prises en charge, consultez Configuration requise.

.NET Framework

Prise en charge dans : 2.0, 1.1, 1.0

Ajouts de la communauté

AJOUTER
Afficher:
© 2016 Microsoft