Ambrosio o cómo crear un servicio de Windows obediente en .NET.
Últimamente he estado programando un servicio de Windows para que el sistema realice de manera periódica y en segundo plano unas determinadas tareas. En mi caso concreto se trata de replicar unas determinadas tablas desde una base de datos Oracle hacia otra MySQL con una determinada periodicidad en función de cada tabla (unos datos son más críticos y necesitan actualizarse cada hora, otros menos variables los actualizamos una vez al día durante las horas valle de actividad). El caso es que con VisualBasic.NET me ha resultado bastante sencillo crearlo y después instalarlo, así que paso a explicar un ejemplo de cómo hacer un sencillo servicio de Windows.
Paso 1. Creamos el proyecto.
Para empezar simplemente iniciamos VisualStudio.NET (en mi caso 2005) y seleccionamos la opción para crear un nuevo proyecto. Ahí seleccionamos Servicio de Windows, le damos un nombre agradable (a poder ser más que WindowsService1, por ejemplo ServicioAlertas) y aceptamos. Nos aparecerá directamente la clase Service1.vb que también podemos renombrar a algo más intuitivo como clsAlert.vb.
Paso 2. Agregamos un instalador.
En la vista diseño de la clase que se nos ha creado hacemos clic con el botón derecho del ratón y seleccionamos la opción Agregar instalador. Con esto se nos creará la clase ProjectInstaller.vb que contiene dos controles: ServiceInstaller1 y ServiceProcessInstaller1. En mi caso renombro estos dos controles simplemente para eliminarles el 1 final (maniático que es uno). Del código de ProjectInstaller.vb nos olvidaremos por completo, pero vamos a hacer algún ajuste en las propiedades de estos dos controles.
Paso 3. Configuramos el instalador.
En el control ServiceInstaller modificamos las propiedades DisplayName y ServiceName para dejarlas ambas en ServicioAlertas. Modificamos también la propiedad StartType para dejarla en Automatic. Esto último sirve para que después cuando instalemos el servicio, éste quede puesto para que arranque automáticamente al iniciarse el sistema operativo. Si no se desea este comportamiento, ajustar esta propiedad según convenga. Es decir:
ServiceName: ServicioAlertas
StartType: Automatic
En el control ServiceProcessInstaller modificamos la propiedad Account para dejarla en LocalSystem. Esto indica qué tipo de cuenta se utilizará para ejecutar el servicio. Podemos dejarla en User, pero después al instalar el servicio pedirá cuenta de usuario y contraseña, así que yo recomiendo pasarla a LocalSystem. Así pues:
Con la clase ProjectInstaller.vb hemos terminado ya por completo, ahora nos centraremos en clsAlert.vb.
Paso 4. Programamos el servicio.
Accedemos al código de la clase clsAlert.vb y observamos que por defecto ya se nos han generado dos métodos: OnStart y OnStop. Está claro para lo que sirven, ¿no? Eso es, para configurar qué hacer y cómo para arrancar y detener el servicio. Personalmente no utilizo el OnStop para nada, así que no hablaré de él, pero por supuesto el que esté interesado puede buscar más información en la propia ayuda del IDE o en internet. Me voy a centrar en el OnStart y voy a ponerle un temporizador para que cada 5 segundos me escriba en un log la hora actual. Sí, lo sé, es un servicio de alertas mediocre, pero servirá como ejemplo de código sencillo con el que programar un servicio y hacer uso, además, de un temporizador (cosa terriblemente útil en ocasiones).
Muestro el código íntegro que dejo pues en la clase clsAlert.vb:
' Author: Albert Mata (www.albertmata.net)
' Date: 20080723
' Description: Class to show how to create a Windows service and how
' to work with a timer.
'--------------------------------------------------------------------
Public Class clsAlert
'----------------------------------------------------------------
' Attributes.
'----------------------------------------------------------------
Private DBTimer As System.Timers.Timer
'----------------------------------------------------------------
' Starts service.
'----------------------------------------------------------------
Protected Overrides Sub OnStart(ByVal args() As String)
'Creating timer with interval = 5000 milisec = 5 seconds.
DBTimer = New System.Timers.Timer(5000)
DBTimer.Enabled = True
AddHandler DBTimer.Elapsed, AddressOf Me.ShowAlert
End Sub
'----------------------------------------------------------------
' Stops service.
'----------------------------------------------------------------
Protected Overrides Sub OnStop()
'Void, as I'm not using this method.
End Sub
'----------------------------------------------------------------
' Main process executed every time DBTimer gives a signal.
'----------------------------------------------------------------
Private Sub ShowAlert(ByVal source As Object, _
ByVal e As System.Timers.ElapsedEventArgs)
DBTimer.Enabled = False
Dim LogFile As New System.IO.StreamWriter("C:\log.txt", True)
LogFile.WriteLine("Alerta www.albertmata.net - " & Date.Now)
LogFile.Close()
DBTimer.Enabled = True
End Sub
End Class
Con esto tenemos terminado nuestro servicio de Windows. Ahora sólo nos falta instalarlo.
Paso 5. Generamos el ejecutable.
Generamos el ejecutable de nuestro servicio (Generar o Volver a generar). A partir de aquí no necesitamos más el IDE, de modo que podemos cerrarlo. A partir de ahora sólo necesitamos el .exe que se nos acaba de generar y un par de archivos .bat que vamos a crear a continuación (podríamos no generarlos y escribir las instrucciones directamente en línea de comandos, pero a mí me resulta más cómodo hacerlo en archivos batch). El archivo .exe (que encontramos en la carpeta bin/Release de nuestro proyecto ServicioAlertas) lo copiaremos en una ruta más corta (C:\). Y los dos archivos .bat que necesitamos son los siguientes:
Instalador.bat
"C:\ServicioAlertas.exe"
pause
Desinstalador.bat
"C:\ServicioAlertas.exe"
pause
En ambos las dos primeras líneas deben ser una única línea continuada (el ancho del blog no lo permite) y la ruta de la aplicación InstallUtil puede variar ligeramente en función de la versión del Framework que estemos utilizando. Basta con verificarlo con el Explorador de Windows y modificarla según convenga.
Para lo que sirven está claro: uno instala el servicio y el otro lo desinstala.
Paso 6. Instalamos el servicio.
Simplemente ejecutamos el archivo Instalador.bat y se nos abrirá una ventana de línea de comando con el proceso de la instalación terminando exitosamente. Ahora nos vamos a Panel de control - Herramientas administrativas - Servicios y encontraremos nuestro servicio ServicioAlertas. Lo iniciamos y observaremos al cabo de pocos segundos que en la ruta C:\ se nos ha creado un archivo log.txt. Si dejamos el servicio un rato funcionando y después lo detenemos veremos que este archivo ha quedado más o menos así:
Alerta www.albertmata.net - 23/07/2008 21:12:23
Alerta www.albertmata.net - 23/07/2008 21:12:28
Alerta www.albertmata.net - 23/07/2008 21:12:33
Alerta www.albertmata.net - 23/07/2008 21:12:38
Paso 7. Desinstalamos el servicio.
Si en algún momento queremos desinstalar el servicio (si es tan poco útil como ServicioAlertas seguro que querremos) solo debemos ejecutar Desinstalador.bat y el servicio quedará desinstalado (tendremos que refrescar la lista de servicios para ver que efectivamente así es).
Con esto queda visto el tema de los servicios de Windows. En internet se puede encontrar mucha otra información al respecto (p.ej. ésta en CodeGuru) en la que nos alertan de no utilizar MsgBox y similares en un servicio porque suelen dar problemillas.
Tags: .NET, Batch, framework, installutil, servicio windows, timer
Octubre 17th, 2008 at 04:20
Muchas gracias por esta información, llevaba bastante buscando y no había encontrado un ejemplo tan práctico como este, de verdad, muchísimas gracias.
Octubre 17th, 2008 at 08:04
Pues muchísimas de nada, encantado de que te haya sido útil...
Octubre 24th, 2008 at 10:14
Perfecto!! era lo que buscaba, me ha quedado claro como el agua, por cierto no se si puedes ayudarme, tengo que crear una carpeta caliente “HotFolder” donde cuando ponga un archivo PDF me salga impreso en una impresora determinada, se te ocurre algo?, gracias por adelantado,, un saludo..
Octubre 24th, 2008 at 10:42
Ostras, primera vez que oigo ese concepto de 'hot folder', así que ni idea, pero puestos a imaginar... igual puedes crear un servicio que cada X segundos revise los archivos en un directorio (puede mantener un registro en un archivo .log) y cuando encuentre uno nuevo ejecute la acción que sea (mandarlo a imprimir, en este caso). ¡De hecho me gusta la idea, igual un día de estos desarrollo algo así
Un saludo.
Enero 23rd, 2009 at 21:20
Muchas gracias por el ejemplo, fue de gran ayuda, sobre todo como instalarlo.
Me dio el siguiente error:
No se encontro 'Sub Main' en 'ServicioAlertas.Service1'
para corregir este error, Solo escoji como Objeto inicial ServicioAlertas.clsAlert
Gracias.
Abril 9th, 2009 at 00:10
Megustaría aportar un articulo parecido en visual studio 2008 con c# utilizando hilos.
http://www.algoritmosen.net/Lecciones/LeccionesenVisualStudio/Implementar_Servicio_Windows/tabid/92/Default.aspx
Julio 2nd, 2009 at 23:50
Excelente ejemplo. saludos