Condividi tramite


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

View

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