Applicazioni Windows Service
|
Domande
|
Applicazioni Windows Service
Mettetevi comodi... Un servizio e' un'applicazione, per sistemi windows di tipo NT, che
gira in background. Cio' significa che e' in esecuzione indipendentemente dagli
utenti che accedono al computer. I servizi possono essere lanciati
addirittura in fase di boot, quando l'utente non ha ancora modo di accedere.
Essi hanno funzioni speciali e non richiedono un'interfaccia grafica,
quindi non interferiscono con l'utente. In realta' e' possibile renderli
interattivi, ma con il framework .NET questo e' diventato piu' complicato,
forse per scoraggiarne l'approccio.
Queste applicazioni sono, teoricamente, in esecuzione fino a quando non
si chiude windows. E' possibile controllarli, cioe', fermarli e farli
ripartire, verificarne lo stato. I servizi girano in un contesto di
sicurezza proprio, in genere impersonificano un particolare utente che ha i
diritti adeguati alla funzione che devono svolgere.
Lo sviluppo di un servizio comporta notevoli differenze rispetto allo
sviluppo di una semplice applicazione. Un servizio deve essere
installato prima che possa essere eseguito. Non e' possibile eseguirlo
immediatamente nell'IDE o farne il debug. In .NET, oltre al servizio, bisogna
creare i suoi componenti d'installazione e registrazione. In sostanza bisogna
creare il suo progetto di Setup.
In Visual Studio .NET, si puo' implementare un servizio in due modi:
creare un progetto Windows Service oppure creare un progetto vuoto. Noi
analizzeremo il secondo caso che ci permette di comprendere a fondo il
meccanismo che realizza un servizio. Nel primo metodo, lo scheletro
del servizio viene gia' fornito dall'ambiente di sviluppo e a noi
spetta implementare le funzionalita'.
Attenzione. Poiche' utilizzo la versione in inglese sia di
windows che di VS.NET, faro' riferimento alla versione inglese sia per quanto
riguarda le etichette
dei menu, sia per nomi degli oggetti del sistema ed altro.
Architettura di un Servizio
La struttura di un servizio e' incapsulata nella classe ServiceBase.
Qualsiasi servizio, quindi, e' una classe che deriva da ServiceBase.
ServiceBase espone i seguenti metodi che noi sovrascriamo per
adattarli al nostro scopo. Questi metodi sono:
-
OnStart
- Eseguito quando il servizio parte
-
OnPause- Eseguito quando il servizio viene messo in pausa
-
OnStop
- Eseguito quando il servizio e' stoppato
-
OnContinue
- Eseguito quando si vuole continuare dopo la pausa
-
OnShutDown
- Eseguito quando il sistema sta per essere spento
-
OnCustomCommand
- Eseguito per notificare un comando Custom
-
OnPowerEvent
- Eseguito in risposta ad un evento Power Management
E' compito di un Service Controller chiamare tali metodi per
gestire il servizio. Il Service Controller
Manager (SCM) di windows e' uno di questi controller. Su windows 2000, ad esso si accede con
il tasto destro del mouse su MyComputer e quindi manage. Un
altro controller e' implementato direttamente nell'IDE di Visual Studio .NET ed
altri ancora si implementano con la classe ServiceController.
Ci sono altre due classi che concorrono allo sviluppo di un service.
Esse sono: ServiceProcessInstaller e ServiceInstaller.
Queste, in genere, vengono gestite trasparentemente dall'IDE tramite
interfaccia grafica.
Come ogni programma, un servizio necessita di un main
entry point statico, nel quale instanziare il servizio e chiamare il
metodo Run della classe ServiceBase che e' il motore del servizio.
La classe ServiceBase fornisce anche una serie di proprieta'
utili per caratterizzare il comportamento del servizio:
-
CanStop
- Indica se il servizio e' stoppabile o meno
-
CanShutDown
- Indica se il servizio ricevera' la notifica di shutdown
-
CanPauseAndContinue
- Indica se il servizio puo' essere messo in pausa
-
CanHandlePowerEvent
- Indica se il servizio ricevera la notifica di Power Management
-
AutoLog - Se True, verranno scritti
automaticamente messaggi informativi nel Log degli eventi del sistema
Esempio:
Il seguente codice fa', dell'esempio del FileSystemWatcher, presentato in un
altro articolo, un servizio di windows. Non avendo a disposizione un
interfaccia grafica, ci limitiamo ad accodare gli eventi della directory
"desktop" in un file di log chiamato: c:\SampleService.txt. Ricordiamo
che gli eventi a cui siamo interessati sono creazione, cancellazione, modifica
e rinominazione di file e directory.
1) Innanzitutto, come detto, deriviamo la classe da ServiceBase.
Il costruttore inizializza il servizio. ServiceName da'
il nome al servizio, lo chiamiamo "SampleService", come la
classe. Esso puo' essere stoppato e messo in pausa. Notate che abilitiamo l'AutoLog:
il servizio scrivera' automaticamente delle entry nell'Application
Event Log di sistema.
Public Class SampleService
Inherits System.ServiceProcess.ServiceBase
Private m_watcher As System.IO.FileSystemWatcher
'
' Costruttore del SampleService
'
Public Sub New()
Me.ServiceName = "SampleService"
Me.CanStop = True
Me.CanPauseAndContinue = True
Me.AutoLog = True
End Sub
'
' Qui verra' inserito il resto del codice...
'
End Class
2) Ora vediamo come implementare i comandi standard OnStart, OnStop, etc. OnStart
e' utilizzata per inizializzare il compito del servizio, nel nostro
caso facciamo il setup del FileSystemWatcher. In OnStop, ci interessa
disabilitare gli eventi del watcher. OnPause ed OnContinue disabilitano ed
abilitano gli eventi del watcher.
'
' Gestori degli eventi del SampleService
'
Protected Overrides Sub OnStart(ByVal args() As String)
watcher = New System.IO.FileSystemWatcher()
watcher.EnableRaisingEvents = False
watcher.Path = "C:\Documents and Settings\a\Desktop\"
watcher.NotifyFilter = IO.NotifyFilters.LastAccess Or _
IO.NotifyFilters.LastWrite Or _
IO.NotifyFilters.DirectoryName Or _
IO.NotifyFilters.FileName
watcher.Filter = "*.txt"
AddHandler watcher.Created, AddressOf OnCreated
AddHandler watcher.Changed, AddressOf OnChanged
AddHandler watcher.Deleted, AddressOf OnDeleted
AddHandler watcher.Renamed, AddressOf OnRenamed
watcher.EnableRaisingEvents = True
End Sub
Protected Overrides Sub OnStop()
watcher.EnableRaisingEvents = False
End Sub
Protected Overrides Sub OnPause()
watcher.EnableRaisingEvents = False
End Sub
Protected Overrides Sub OnContinue()
watcher.EnableRaisingEvents = True
End Sub
3) Seguono i gestori degli eventi del FileSystemWatcher, sono gli stessi gia'
utilizzati nell'esempio del FileSystemWatcher. In questo caso inviano il
messaggio al metodo Logger che lo scrive sul file di log, accodandolo
ai precedenti.
'
' Gestori di eventi del FileSystem
'
Private Sub OnCreated(ByVal sender As Object, _
ByVal e As System.IO.FileSystemEventArgs)
Dim msg As String
msg = "Created: """ & e.Name & """"
Logger(msg)
End Sub
Private Sub OnChanged(ByVal sender As Object, _
ByVal e As System.IO.FileSystemEventArgs)
Dim msg As String
msg = "Changed: """ & e.Name & """"
Logger(msg)
End Sub
Private Sub OnDeleted(ByVal sender As Object, _
ByVal e As System.IO.FileSystemEventArgs)
Dim msg As String
msg = "Deleted: """ & e.Name & """"
Logger(msg)
End Sub
Private Sub OnRenamed(ByVal sender As Object, _
ByVal e As System.IO.RenamedEventArgs)
Dim msg As String
msg = "Renamed: """ & e.OldName & """ to """ & e.Name & """"
Logger(msg)
End Sub
4) Logger gestisce l'archiviazione dei messaggi degli eventi relativi al
filesystem. Apre un file di testo c:\SampleService.txt in modalita'
append e vi scrive sia la data dell'evento che il tipo di evento.
'
' Gestione del file di log
'
Private Sub Logger(ByVal msg As String)
Dim fs As Stream = New FileStream("c:\SampleService.txt", _
FileMode.Append)
Dim sw As StreamWriter = New StreamWriter(fs)
sw.WriteLine(Now)
sw.WriteLine(msg)
sw.Close()
fs.Close()
End Sub
5) Questo e' il main entry point della nostra applicazione. Facciamo partire il servizio
eseguendo il metodo Run della classe ServiceBase
e ad esso forniamo una nuova istanza del nostro servizio.
'
' Entry Point dell'applicazione
'
Shared Sub main()
System.ServiceProcess.ServiceBase.Run(New SampleService())
End Sub
Lo sviluppo del servizio non termina qui. Ora bisogna creare quelle
automazioni che siano in grado si installarlo.
Aggiunta degli installer
Fortunatamente l'aggiunta degli installer non comporta necessariamente
scrittura di codice da parte nostra. Ci limiteremo a settare qualche
proprieta'.
-
Cliccate sull'interfaccia grafica del servizio che dovrebbe essere
vuota, poi selezionate la finestra delle proprieta'. In fondo a tale finestra,
nella zona grigia, compare un link Add Installer.
-
Cliccando tale link due installer vengono aggiunti al progetto, ServiceProcessInstaller1
e ServiceInstaller1.
-
Selezionate le proprieta' di ServiceInstaller1 ed impostate
ServiceName col nome del nostro servizio. Il nome
deve essere lo stesso che abbiamo dato nel costruttore: "SampleService".
Dovessimo cambiarlo nel costruttore, bisogna aggiornarlo anche qui.
-
Impostate la proprieta' StartType ad Automatic.
-
Selezionando le proprieta' di ServiceProcessInstaller1,
impostate Account con il valore LocalSystem.
Note:
StartType puo' assusmere i seguenti valori che
sono conrollabili successivamente dal SCM.
-
Manual - Il servizio
deve essere avviato manualmente, dopo ogni boot
-
Automatic- Il servizio
sara' avviato automaticamente dopo il boot
-
Disabled - Il servizio
e' disabilitato, non puo' essere avviato
Account puo' assusmere i seguenti valori che sono conrollabili
successivamente dal SCM: User, LocalService,
LocalSystem, NetworkService. Per maggiori
dettagli vedere Specifying the Security Context for Services nella
documentazione di Visual Studio .NET.
Creazione del progetto di Setup
Aggiungiamo un progetto di setup:
-
File menu -> Add Project -> New Project.
-
Scegliete la cartella Setup and Deployment Projects.
-
Selezionate un Setup Project, nominandolo SampleServiceSetup.
Inseriamo il servizio SampleService.exe nel setup:
-
Nel Solution Explorer, clicchiamo col destro su SampleServiceSetup
-> Add -> Project Output. Otterremo la dialog
box chiamata Add Project Output Group.
-
SampleService
dovrebbe essere gia' selezionato.
-
Selezionate Primary Output
dalla lista.
Aggiungiamo azioni personalizzate al setup:
-
Nel Solution Explorer, clicchiamo col destro su SampleServiceSetup
-> View -> Custom Actions. Otterremo l'editor
chiamato Custom Actions.
-
Nell'editor, cliccate col destro sul nodo Custom Actions,
scegliendo Add Custom Action.
-
Doppio click su Application Folder, selezionare Primary
Output from SampleService(Active). Ok. Otteniamo l'effetto di
aggiungere il primary output alle seguenti azioni: Install,
Commit, Rollback, Uninstal.
Test
Adesso si puo' compilare l'intero lavoro, cliccando col destro, nel Solution
Explorer, su SampleServiceSetup e scegliere Build.
Dopo ogni modifica apportata ai progetti, si puo' compilare tutto in questo
stesso modo.
Per installare il progetto, e' possibile cliccare ancora con il destro su SampleServiceSetup,
e scegliere Install. La disinstallazione e' analoga. Nelle cartelle di
progetto create da VS.NET e' anche disponibile il file eseguibile per il Setup.
Lanciamo l'SCM oppure il Server Explorer nell'IDE ed
individuiamo, fra i nodi, il nostro servizio. Facciamolo partire. Cercate nel
log degli eventi per controllare i messagi inviati dal nostro servizio. Giocate
con qualche file di testo sul desktop, rinominandolo etc. Poi controllate il
contenuto del file c:\SampleService.txt e vedete se il servizio
sta loggando gli eventi.
Ultimo aggiornamento 13/01/2004
|