Esta documentación está archivada y no tiene mantenimiento.

ServiceBase (Clase)

Proporciona una clase base para un servicio que existirá como parte de una aplicación de servicio. Deberá derivarse de ServiceBase cuando se cree una nueva clase de servicio.

Espacio de nombres: System.ServiceProcess
Ensamblado: System.ServiceProcess (en system.serviceprocess.dll)

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

Derive de ServiceBase al definir la clase de servicio de una aplicación de servicio. Cualquier servicio útil reemplaza los métodos OnStart y OnStop. Para obtener funcionalidad adicional, puede reemplazar OnPause y OnContinue por un comportamiento específico en respuesta a cambios en el estado del servicio.

Un servicio es un ejecutable de ejecución larga que no admite una interfaz de usuario y que puede no ejecutarse en la cuenta de usuario que ha iniciado la sesión. El servicio puede ejecutarse sin que ningún usuario haya iniciado una sesión en el equipo.

De forma predeterminada, los servicios se ejecutan en la cuenta de sistema, que no es igual que la cuenta de administrador. No puede cambiar los derechos de la cuenta de sistema. De modo alternativo, puede utilizar ServiceProcessInstaller para especificar una cuenta de usuario en la que se ejecutará el servicio.

Un ejecutable puede contener más de un servicio, pero tiene que contener un componente ServiceInstaller independiente para cada uno de los servicios. La instancia de ServiceInstaller registra el servicio en el sistema. Asimismo, el instalador asocia cada servicio a un registro de eventos que puede utilizar para registrar comandos de servicio. La función main() del ejecutable define qué servicios deben ejecutarse. El directorio de trabajo actual del servicio es el directorio del sistema, no el directorio en el que está situado el ejecutable.

Cuando se inicia un servicio, el sistema busca el ejecutable y ejecuta el método OnStart de ese servicio, contenido dentro del ejecutable. Sin embargo, ejecutar el servicio no equivale a ejecutar el ejecutable. El ejecutable solamente carga el servicio. Se obtiene acceso al servicio (por ejemplo, lo inicia y lo detiene) mediante el Administrador de control de servicios.

El ejecutable llama al constructor de la clase derivada de ServiceBase la primera vez que se llama a Start para el servicio. Se llama al método de control de comandos OnStart inmediatamente después de que se ejecute el constructor. El constructor no se vuelve a ejecutar después de la primera vez que se ha cargado el servicio, por lo que es necesario separar el procesamiento realizado por el constructor del realizado por OnStart. Cualquier recurso que OnStop pueda liberar tiene que crearse en OnStart. La creación de recursos en el constructor impide que estos se creen adecuadamente si se inicia de nuevo el servicio una vez que OnStop ha liberado los recursos.

El Administrador de control de servicios (SCM, Service Control Manager) permite la interacción con el servicio. Puede utilizar el SCM para pasar comandos Iniciar, Detener, Pausar, Continuar o comandos personalizados al servicio. El SCM utiliza los valores de las propiedades CanStop y CanPauseAndContinue para determinar si el servicio acepta los comandos Detener, Pausar o Continuar. Detener, Pausar y Continuar sólo estarán habilitados en los menús contextuales del SCM si la propiedad CanStop o CanPauseAndContinue correspondiente es true en la clase de servicio. Si está habilitado, el comando se pasa al servicio y se llama a OnStop, OnPause o OnContinue. Si la propiedad CanStop, CanShutdown o CanPauseAndContinue es false, no se procesará el método de control de comandos correspondiente (como OnStop), aunque se haya implementado el método.

Puede utilizar la clase ServiceController para realizar mediante programación lo que el SCM realiza mediante una interfaz de usuario. Es posible automatizar las tareas disponibles en la consola. Si la propiedad CanStop, CanShutdown o CanPauseAndContinue es true, pero no implementó el método de control de comandos correspondiente (como OnStop), el sistema produce una excepción y omite el comando.

No tiene que implementar el método OnStart, OnStop ni ningún otro método en ServiceBase. Sin embargo, el comportamiento del servicio se describe en OnStart, por lo que, como mínimo, tendrá que reemplazarse este miembro. Debe establecerse el nombre del servicio en la función main() del ejecutable. El nombre de servicio que se establece en main() debe coincidir exactamente con la propiedad ServiceName del instalador del servicio.

Puede utilizar InstallUtil.exe para instalar servicios en el sistema.

NotaNota

Es posible especificar un registro que no sea el registro de eventos de aplicación para recibir la notificación de llamadas de servicio, pero ni la propiedad AutoLog ni la propiedad EventLog pueden escribir en un registro personalizado. Establezca AutoLog en false si no desea utilizar el registro automático.

En el ejemplo siguiente se deriva una implementación simple del servicio de la clase ServiceBase. El servicio controla diversos comandos de servicio, entre ellos los comandos Detener, Iniciar, Pausar, Continuar y comandos personalizados.

// 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

Los miembros estáticos públicos (Shared en Visual Basic) de este tipo son seguros para la ejecución de subprocesos. No se garantiza que los miembros de instancias sean seguros para la ejecución de subprocesos.

Windows 98, Windows 2000 SP4, Windows Server 2003, Windows XP Media Center, Windows XP Professional x64, Windows XP SP2, Windows XP Starter Edition

.NET Framework no admite todas las versiones de cada plataforma. Para obtener una lista de las versiones admitidas, vea Requisitos del sistema.

.NET Framework

Compatible con: 2.0, 1.1, 1.0
Mostrar: