Creare un servizio di versioning in Visual Basic .NET (it-IT)
Introduzione
In questo articolo vedremo come poter creare un servizio di Windows utilizzando Visual Basic .NET. Analizzeremo inoltre l'installazione del servizio creato, sia nel contesto di test che nell'ambito di effettiva destinazione. Al termine dell'articolo, otterremo un servizio molto rudimentale che esegue il versioning dei files presenti in una data cartella. Tale progetto potrà essere ampliato e/o modificato a seconda delle necessità, fornendo un esempio sulla base del quale sviluppare ulteriori soluzioni.
Cos'è un servizio
Con il termine «servizio» si intende, in ambito Windows, un programma (o più genericamente, un qualsiasi processo) la cui esecuzione tende a rimanere trasparente all'utente ed indipendente dall'interazione di quest'ultimo. Tipicamente, il servizio viene impiegato per aggiungere funzionalità al contesto su cui si trova ad essere eseguito. In questa definizione ricadono, per fare un esempio immediato, i moduli di protezione in real-time dei vari antivirus in commercio. Si tratta cioè di programmi scritti appositamente per svolgere compiti ripetitivi verso i quali l'attenzione dell'utente può essere limitata, quando non addirittura assente.
Windows possiede ovviamente tutta una serie di servizi standard, con i quali gestisce diverse funzionalità di base, ma non impedisce di arricchire la schiera di tali processi con ulteriori moduli utili per l'utilizzatore. Ciò che realizzeremo in questo articolo va appunto a ricadere in tale definizione.
Accedere alla lista dei servizi
Per visionare e gestire la lista dei servizi installati, esistono differenti strade, ormai da tempo quasi uniformate trasversalmente rispetto alla versione di OS in utilizzo. Il lettore sicuramente conoscerà la voce «Servizi», da Pannello di Controllo (raggiungibile anche utilizzando la «Gestione Computer», essendo services.msc uno snap-in dell'utility Microsoft Management Console). Un'altra possibilità è rappresentata dal comando DOS NET START, e - sempre per gli amanti della linea di comando - menzioniamo il programma sc.exe, che permette un'interazione non grafica con i servizi.
In queste righe non spendiamo ulteriore tempo nell'analisi di tali strumenti, rimandando alle rispettive guide qualora ve ne fosse necessità.
Creare un servizio con Visual Studio
Operazioni preliminari
Come anticipato nell'introduzione, creeremo un semplice servizio che avrà la finalità di monitorare una determinata cartella, salvando una copia dei files in essa contenuti qualora subiscano variazione.
Apriamo Visual Studio e - creando un nuovo progetto Visual Basic - selezioniamo il template Classic Desktop » Windows Service. Nel nostro esempio, il progetto avrà nome VersioningSvc.
Visual Studio preparerà la soluzione utilizzando il template selezionato, predisponendo un modulo per il servizio di nome Service1.vb. Vogliamo assegnare al servizio un nome differente, e - dal momento che tale stringa è referenziata in punti diversi del codice - utilizzeremo l'utility Sostituzione rapida (Ctrl+H), come mostra l'immagine seguente:
Rinominiamo ancora il file Service1.vb come VersioningSvc.vb.
Entrando poi nel sorgente di quest'ultimo, vedremo come siano stati predisposti due eventi, ovvero OnStart ed OnStop. Si tratta, molto semplicemente, degli eventi che gestiscono le fasi di avvio e di termine del servizio stesso.
Protected Overrides Sub OnStart(ByVal args() As String)
' Add code here to start your service. This method should set things
' in motion so your service can do its work.
End Sub
Protected Overrides Sub OnStop()
' Add code here to perform any tear-down necessary to stop your service.
End Sub
OnStart() diventa pertanto il nostro punto di ingresso. Svilupperemo il servizio di versioning a partire da questo evento.
Implementare la logica applicativa
Al di là di quanto visto finora, non vi sono particolari differenze tra lo sviluppo di una qualsiasi applicazione desktop ed un servizio. In questo secondo caso, saremo probabilmente più orientati all'automatizzazione (mentre programmi di altro genere si baseranno in parte sull'interazione utente), ma gli strumenti a nostra disposizione sono gli stessi di sempre. Per sviluppare il nostro servizio di versioning, ci baseremo sulla classe FileSystemWatcher.
FileSystemWatcher è una classe che mette a disposizione dello sviluppatore degli strumenti di monitoring delle directory e dei files in esse contenuti. Attraverso alcuni eventi, permette di controllare la tipologia di operazioni svolta sui documenti, come la creazione, la modifica, l'eliminazione, ecc.. Nel nostro caso, data una certa cartella vorremo monitorare le sole modifiche che avvengono sui files. La logica che adotteremo è semplice: a partire da un certo folder, quando su un file in essa contenuto verrà recepita una modifica, faremo una copia del file stesso in una sottodirectory dedicata, aggiungendo il timestamp di tale operazione al nome del file. Relativamente all'oggetto FileSystemWatcher che creeremo, andremo quindi a gestire il solo evento Changed.
La nostra classe (e, di fatto, l'intero codice del servizio) diventa pertanto il seguente:
Imports System.IO
Public Class VersioningSvc
Const wPath As String = "C:\temp\"
Const wExte As String = ".txt"
Dim WithEvents fsw As FileSystemWatcher
Protected Overrides Sub OnStart(ByVal args() As String)
fsw = New FileSystemWatcher(wPath, "*" & wExte)
fsw.NotifyFilter = NotifyFilters.LastWrite
fsw.EnableRaisingEvents = True
End Sub
Protected Overrides Sub OnStop()
MyBase.OnStop()
End Sub
Private Sub fsw_Changed(sender As Object, e As FileSystemEventArgs) Handles fsw.Changed
Try
Dim fI As New FileInfo(e.FullPath)
If Not (fI.Exists) Then Exit Sub
Dim vPath As String = wPath & "\.versions\"
Dim fO As New FileInfo(vPath & e.Name)
If Not (fO.Exists) Then
Dim dI As New DirectoryInfo(vPath)
If Not (dI.Exists) Then dI.Create()
End If
fI.CopyTo(vPath & fI.Name & "_" & Now.ToString("yyyyMMdd_HHmmss"))
Catch ex As Exception
End Try
End Sub
End Class
Volendo riassumerne il funzionamento, si nota come in apertura di classe vengano definiti il path da monitorare e la tipologia file di interesse (tramite sua estensione). Durante l'evento OnStart del servizio, verrà inizializzato l'oggetto FileSystemWatcher affinché possa monitorare le modifiche sulla base dell'ultima data di scrittura dei files. Infine, il settaggio della proprietà EnableRaisingEvents a True farà sì che il monitoraggio vero e proprio abbia inizio.
Di conseguenza, ogni qualvolta verrà modificato un file nella cartella preposta, verrà invocato il metodo Changed. Come si noterà, in esso vengono eseguite alcune semplici operazioni e controlli. Il primo, è che il file recepito sia effettivamente esistente. Se tale condizione è soddisfatta, sulla base del path di origine viene prodotta una sottodirectory di nome "\versions\, e - successivamente - una copia del file stesso sarà posizionata in essa, corredata da timestamp.
In questo modo, nella cartella "\versions\ potremo risalire ad ogni modifica effettivamente subita dai files della cartella di livello superiore, permettendo quindi di gestire una vera e propria cronostoria dei files stessi.
Predisporre gli installer di servizio
Per poter inserire il proprio servizio tra quelli gestibili dagli snap-in di sistema, dovremo aggiungere alla nostra soluzione un installer, attraverso cui eseguire poi l'installazione in Windows. Facciamo quindi click con il tasto destro sulla videata di Design della classe del servizio, e selezioniamo la voce di menù «Add Installer»
Verranno creati due oggetti, ovvero ServiceInstaller1 e ServiceProcessInstaller1. Si tratta di oggetti attraverso i quali potremo definire alcune informazioni di dettaglio del nostro servizio, come ad esempio il nome da mostrare nella lista servizi, e la descrizione, ma anche specificare parametri più importanti, come la tipologia di avvio del servizio e l'utenza da impiegare per la sua esecuzione.
Nella prossima immagine, vediamo come siano state definite le proprietà DisplayName e Description dell'oggetto ServiceInstaller1, e come il suo avvio sia stato impostato ad «Automatic». Sull'oggetto ServiceProcessInstaller1 è stata indicata la proprietà Account con valore LocalSystem, in modo che il servizio abbia un livello piuttosto elevato di privilegi di esecuzione.
Terminata questa fase, possiamo procedere alla compilazione della soluzione, che produrrà - come di consueto - un file eseguibile, da utilizzare però in congiunzione con l'utility installutil.exe per effettuare l'installazione vera e propria del servizio.
Prima di eseguire le operazioni di build, assicuriamoci che - nelle proprietà del progetto - l'oggetto di avvio sia la nostra classe.
Installiamo il servizio
Eseguiamo quindi il Developer Command Prompt for Visual Studio: è sufficiente digitare tale stringa nella box di ricerca di Windows per fare in modo che venga proposta. Per essere certi dell'esito positivo dell'installazione, sarà opportuno eseguire il Prompt come amministratori.
Digitiamo quindi il comando seguente, dove la stringa <PERCORSO_ESEGUIBILE> sarà ovviamente da sostituire con il percorso su disco in cui reperire l'exe da poco compilato.
C:\WINDOWS\system32>installutil <PERCORSO_ESEGUIBILE>
Una serie di informazioni a video ci mostrerà l'esito dell'installazione ed eventuali messaggi di criticità da approfondire.
Nel nostro caso, come si nota, la procedura è andata a buon fine. Non ci resta quindi che testare l'effettiva funzionalità dell'applicazione.
Esecuzione di test
Eseguiamo services.msc (o semplicemente accediamo alla scheda Servizi da Gestione Computer), e cerchiamo il nostro servizio, che inizialmente risulterà inattivo.
Si noti nello screenshot a seguire come nome e descrizione corrispondano a quanto digitato relativamente alle proprietà dell'oggetto ServiceInstaller1.
Premiamo quindi «Avvia»: da questo momento, le operazioni eseguite sulla cartella specificata saranno monitorate. Possiamo vedere la fase di avvio servizio e di funzionalità dello stesso nel video dimostrativo che segue.
Video dimostrativo
Disinstallare il servizio
Una volta conclusa la fase di test, o semplicemente se desideriamo ritoccare il nostro servizio, o disinstallarlo del tutto, non dovremo far altro che aprire nuovamente il Developer Command Prompt per eseguire installutil.exe, questa volta indicando - oltre al percorso del servizio - il flag di disinstallazione /u.
C:\WINDOWS\system32>installutil /u <PERCORSO_ESEGUIBILE>
Conclusione
Si è qui considerata la stesura di un semplice servizio, al fine di indicare le varie fasi che spaziano tra il suo sviluppo e la sua successiva installazione. Non esistono particolari limiti a ciò che è possibile realizzare in tal senso: il lettore è pertanto invitato a migliorare ed ampliare quanto in oggetto, al fine di sviluppare maggior confidenza con l'argomento, ed arrivare a creare soluzioni complete per le proprie finalità.
Codice sorgente
È possibile scaricare il codice sorgente qui analizzato al seguente link: https://code.msdn.microsoft.com/Creare-un-servizio-di-428d0141
Altre lingue
Il presente articolo è inoltre disponibile nelle seguenti localizzazioni