|
Implementacja usługi
Na samym początku należy uruchomić Visual Studio .NET i stworzyć nowy projekt (Ctrl+Shift+N) VB.NET Windows Service o podanej nazwie (w tym przypadku np.: UslugaMonitorujacaPliki), jak to zobrazowuje rysunek poniżej.

Rys. 1 Tworzenie nowego projektu usługi windows w VB.NET
Po kliknięciu na przycisk OK VS.NET tworzy szablon usługi wraz z dwoma stworzonymi procedurami Sub:
Zauważcie, iż utworzona automatycznie klasa Service1 usługi dziedziczy po klasie System.ServiceProcess.ServiceBase dostępnej w .NET Framework.
Imports System.ServiceProcess Public Class Service1 Inherits System.ServiceProcess.ServiceBase 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 End Class
Kod 1 Procedury OnStart() i OnStop()
Jak widać na kodzie zamieszczonym wyżej, procedura OnStart() pobiera jeden parametr wejściowy args(), który za pomocą tablicy znaków umożliwia użytkownikowi na przekazanie parametrów startu do usługi. Dodatkowo do dwóch procedur utworzonych za pomocą VS.NET istnieje możliwość dodania jeszcze pięciu procedur dostępnych poprzez klasę ServiceBase:
OnContinue()
OnCustomCommand()
OnPause()
OnPowerEvent()
OnShutdown()
W artykule tym, zostaną wykorzystane tylko dwie funkcje OnStart() i OnStop() niezbędne by wytworzyć usługę. Pozwoli ona monitorować określone typy dokumentów (np.: dokumenty Word, tekstowe czy też HTML) znajdujące się na określonej ścieżce na dysku twardym. Dzięki tej opcji, użytkownik będzie mógł łatwo przejrzeć informacje o tym, co się ostatnio działo w jego katalogu, na plikach, które go interesują.
Przy tworzeniu usługi zostanie wykorzystana klasy FileSystemWatcher, dostarczona z .NET Framework.
Na początku należy wytworzyć kod, który będzie ustawiał parametry działania usługi. Tym celu przed deklaracja klasy Service1 należy umieścić import przestrzeni nazw .NET Framework System.IO, a po deklaracji klasy, deklarację zmiennej globalnej odpowiedzialnej za zapis do pliku. Następną czynnością jest oprogramowanie procedury OnStart(), która wykorzysta zaimportowaną przestrzeń nazw oraz zmienną globalną. Kod poniżej pokazuje jedną z możliwych implementacji procedury OnStart():
Imports System.IO ´ ... Dim sr As StreamWriter Protected Overrides Sub OnStart(ByVal args() As String) ´ Tworzy nowy Service obserwujacy pliki i ustawia jego wlasciwosci Dim fswFilesWatcher As New FileSystemWatcher Dim strErr As String Try ´ parametr startu fswFilesWatcher.Path = args(0).ToString fswFilesWatcher.IncludeSubdirectories = args(1).ToString fswFilesWatcher.NotifyFilter = Convert.ToInt16(args(2)) fswFilesWatcher.Filter = args(3).ToString Catch e As Exception ´ Co zrobic wrazie bledu End Try ´ Event Handlers AddHandler fswFilesWatcher.Changed, AddressOf OnFileUpdate AddHandler fswFilesWatcher.Created, AddressOf OnFileChanged AddHandler fswFilesWatcher.Deleted, AddressOf OnFileChanged AddHandler fswFilesWatcher.Renamed, AddressOf OnFileRenamed Me.AutoLog = False Const FILE_NAME = "c:\MonitorLog.log" If Not File.Exists(FILE_NAME) Then sr = File.CreateText(FILE_NAME) Else sr = New StreamWriter(FILE_NAME, True) End If sr.WriteLine("-------------START-------------") sr.WriteLine("MonitorowaniePlikow started At " & Date.Now) sr.WriteLine("-------------------------------") fswFilesWatcher.EnableRaisingEvents = True End Sub
Kod 2 Procedura OnStart()
Na początku został utworzony obiekt FileSystemWatcher a następnie jego atrybutom zostały przypisane parametry (przekazane do zmiennej wejściowej args()) inicjalizujące usługę. Atrybutom, którym zostały przypisane wartości parametru args() są dość intuicyjne (ze względu na nazwę parametru):
Path – ścieżka do katalogu, który ma być monitorowany.
IncludeSubdirectories – czy podkatalogi też mają być monitorowane.
NotifyFilter – ustawienia typu aktywności plików/katalogów, które mają być monitorowane. Do aktywności zalicza się:
LastAccess – data i godzina ostatniego otworzenia pliku
LastWrite – data i godzina ostatniego zapisania pliku
FileName – data i godzina zmiany nazwy pliku
DirectoryName – data i godzina zmiany nazwy katalogu
Filter – określa, jakiego typu pliki mają być monitorowane np.: *.txt oznacza, że pliki tekstowe mają być monitorowane.
Następnie należy określić handlery zdarzeń, które przechwycą zdarzenia (modyfikacja, utworzenia, usunięcie, zmiana nazwy) na plikach. Poniższy kod ilustruje obsłużenie takich zdarzeń:
Public Sub OnFileChanged(ByVal objSource As Object, ByVal e As FileSystemEventArgs) sr.WriteLine(Date.Now & " : " & e.ChangeType.ToString & " : File : " & e.FullPath) End Sub Public Sub OnFileUpdate(ByVal objSource As Object, ByVal e As FileSystemEventArgs) sr.WriteLine(Date.Now & " : Updated : File : " & e.FullPath) End Sub Public Sub OnFileRenamed(ByVal objSource As Object, ByVal e As RenamedEventArgs) sr.WriteLine(Date.Now & " : Renamed : File : " & e.OldFullPath & " to " & e.FullPath) End Sub
Kod 3 Kod do przechwytywania zdarzeń
Standardowo, każda usługa zapisuje swoją aktywność (uruchomienie, zatrzymanie, za pauzowanie) w logu aplikacji, dostępnym pod podglądem zdarzeń. By wyłączyć wpisy do logu aplikacji wystarczy ustawić parametr AutoLog na False w procedurze OnStart():
Me.AutoLog = False
Kod 4 Wyłączenie wpisów do logu aplikacji
Dodatkowo przy uruchamianiu usługi, należy określić plik, do którego będą zapisywane informacje o działaniach na plikach. Jeżeli taki plik nie istnieje to należy go utworzyć, w przeciwnym wypadku otworzyć i zacząć dopisywać informacje na jego końcu.
Const FILE_NAME = "c:\files.log" If Not File.Exists(FILE_NAME) Then sr = File.CreateText(FILE_NAME) Else sr = New StreamWriter(FILE_NAME, True) End If sr.WriteLine("-------------START-------------") sr.WriteLine("MonitorowaniePlikow started At " & Date.Now) sr.WriteLine"-------------------------------")
Kod 5 Utworzenie nowego pliku lub otworzenie już istniejącego
Na końcu należy ustawić parametr EnableRaisingEvents (który określa czy FileSystemWatcher ma monitorować pliki czy nie) na True:
fswFilesWatcher.EnableRaisingEvents = True
Kod 6 Włączenie monitorowania plików
Kod procedury OnStart() włączał i ustawiał zapisywanie monitorowania plików, teraz pora na ustawienie wyłączenia monitorowania plików. W tym celu do procedury OnStop() należy dodać następujący kod (jedyna, ważne linijka to sr.Colse(), zamykająca działanie na pliku, reszta może być dowolnie dobierana w zależności od wymagań):
Protected Overrides Sub OnStop() ´ Zatrzymanie serwisu sr.WriteLine("-------------------------------") sr.WriteLine("MonitorowaniePlikow stopped At " & Date.Now) sr.WriteLine("--------------END--------------") sr.Close() End Sub
Kod 7 Wyłączenie usługi monitorowania plików
Instalowanie usługi
Teraz, gdy kod niezbędny do uruchomienia i zatrzymania usługi został już wytworzony, należy utworzyć kod, który zainstaluje ją w systemie, gdyż przetestowanie jej za pomocą debugingu (F5) czy po prostu otworzeniu utworzonego pliku wykonywalnego *.exe jest niewykonalne. Zanim jednak doda się instalację, należy ustawić nazwę usługi w parametrze ServiceName tak jak to pokazuje rysunek poniżej:

Rys. 2 Ustawienia parametru ServiceName
Następnie w tym samym oknie należy kliknąć Add Installer tak jak to pokazano na rysunku 3.

Rys. 3 Dodanie instalatora usługi
Add Installer doda nowy plik do projektu z dwoma nowymi instancjami klas kolejno ServiceProcessInstaller i ServiceInstaller, które ułatwią konfigurację instalacji i odinstalowania usługi. Obie instancje należy skonfigurować tak jak jest to pokazane na rysunku 4.

Rys. 4 Konfiguracja instancji klas ServiceProcessInstaller i ServiceInstaller
Parametr Account z wartością LocalSystem, używa konta odgrywającego rolę użytkownika, na lokalnym komputerze, bez przywilejów jego plusem jest także umożliwienie anonimowego dostępu do dowolnego zdalnego serwera. Jeżeli w tym polu zostanie podana wartość User, system po instalacji usługi poprosi o podanie użytkownika i hasła do konta, z którego usługa będzie korzystała.
Parametr StartType z standardową wartością Manual mówi usłudze o nie uruchamianiu się dopóki użytkownik tego nie zechce.
Uwaga: Należy się upewnić czy parametr ServiceName (jak pokazano na rysunku 2) ma taką samą nazwę jak parametr ServiceName dla instancji klasy ServiceInstaller (jak pokazano na rysunku 4).
Teraz, gdy wszystkie parametry instalacji zostały ustawione pora zbudować projekt tak jak to pokazano na rysunku 5.

Rys. 5 Budowanie naszego projektu
Posiadając plik wykonywalny, powstały w wyniku zbudowania usługi, trzeba go zainstalować w systemie za pomocą programu InstallUtil dostępnego wraz z .NET Framework. Za pomocą linii poleceń (Start | Uruchom | cmd) należy przejść do katalogu bin aplikacji monitorowania plików i wprowadzić następującą linijkę:
C:\Documents and Settings\Administrator\My Documents\Visual Studio Projects\Uslu gaMonitorujacaPliki\bin>InstallUtil UslugaMonitorujacaPliki.exe
Kod 8 Instalacja usługi z cmd
Uwaga: Jeżeli konsola nie rozpozna programu InstallUtil to zawsze można ten program uruchomić z konsoli Visual Studio .NET Command Prompt (Visual Studio .NET 2003 Command Prompt dla VS.NET 2003) dostępnej w menu Visual Studio .NET Tools.
Po instalacji usługi użytkownik może się upewnić czy aby na pewno została ona zainstalowana w systemie. Może to sprawdzić za pomocą przystawki mmc Usługi dostępnej w narzędziach administratora lub poprzez mmc w Start | Uruchom.

Rys. 6 Usługi
Usługa może zostać uruchomiona za pomocą kliknięcia na niej prawym przyciskiem myszy i wybrawszy opcję Start. Jednakże usługa nie zadziała, zostanie od razu po uruchomieniu zatrzymana. Dzieje się tak, gdyż wymaga ona podania parametrów wejściowych, które można określić w przystawce mmc Usługi, jednak sposób ich wprowadzania wcale nie jest przyjazny użytkownikowi.
Uruchomienie usługi za pomocą kontrolera usługi
Używanie przystawki Usługi do uruchamiania i zatrzymywania wytworzonej wcześniej usługi nie jest przyjazne dla użytkownika, w szczególności przez atrybuty, które muszą zostać do niej przekazane. W celu ułatwienia przekazywania parametrów do usługi należy wytworzyć prostą aplikację windowsową, która umożliwi kontrolowanie wytworzonej usługi. Okno główne aplikacji kontrolującej usługę może wyglądać tak jak pokazano na rysunku 7.

Rys. 7 Główne okno aplikacji
Pierwsza zakładka będzie kontrolowała usługę a druga wszystkie pozostałe usługi dostępne w systemie. By tworzona aplikacja miała dostęp do usług należy na główne okno aplikacji dodać komponent ServiceController, tak jak pokazano to na rysunku 8.

Rys. 8 Dodanie komponentu ServiceController
Komponent ServiceController umożliwia na manipulację (taką jak zatrzymanie, uruchomienie, za pauzowanie) usługami. Wymaga on ustawienia parametrów:
Zakładka pierwsza umożliwia skonfigurowanie parametrów uruchomienia wytworzonej wcześniej usługi. Po kliknięciu na przycisk Start, ustawione parametry są pakowane do tablicy ciągu znaków i przekazywane do usługi za pomocą ServiceController:
Private Sub cmdStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdStart.Click If scServiceController.Status = ServiceProcess.ServiceControllerStatus.Running Then Return Dim args(3) As String args(0) = txtPath.Text args(1) = chkIncludeSubDir.Checked If chkLastAccess.Checked Then args(2) = args(2) Or NotifyFilters.LastAccess If chkLastWrite.Checked Then args(2) = args(2) Or NotifyFilters.LastWrite If chkFileNameChange.Checked Then args(2) = args(2) Or NotifyFilters.FileName If chkDirectoryNamechange.Checked Then args(2) = args(2) Or NotifyFilters.DirectoryName args(3) = cboFileType.Text scServiceController.Start(args) Displaystatus("MonitorowaniePlikow") End Sub
Kod 9 Pakowanie zaznaczonych parametrów i przesłanie ich do usługi
By za pauzować usługę, należy dodać kod odpowiedzialny za zdarzenia Click przycisku Pause. Kod powinien wyglądać następująco:
Private Sub cmdPause_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdPause.Click If scServiceController.CanPauseAndContinue Then scServiceController.Pause() Displaystatus("MonitorowaniePlikow") Else MsgBox("Service cannot be paused.") End If End Sub
Kod 10 Pauzowanie usługi
Zwróćcie uwagę na sprawdzenie czy usługa może być za pauzowana za pomocą parametru CanPauseAndContinue. Z powodu, niezaimplementowania procedury OnPause() w usłudze, nie sprawdzenie czy może ona być za pauzowana spowodowałoby błąd. Podobnie, by zatrzymać usługę, należy upewnić się czy usługa nie została już wcześniej zatrzymana:
Private Sub cmdStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdStop.Click If scServiceController.Status <> ServiceProcess.ServiceControllerStatus.Stopped Then scServiceController.Stop() Displaystatus("MonitorowaniePlikow") End If End Sub
Kod 11 Zatrzymanie usługi
Nie został tutaj zaimplementowany error handling, gdyż usługa może być w fazie przejściowej, przez co error handling nie byłby w 100% pewny – wręcz na pewno zadziałałby przeciwnie do zamierzeń programisty.
Przycisk Show Status, wyświetla status usługi
Private Sub cmdShowStatus_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdShowStatus.Click Displaystatus("MonitorowaniePlikow") End Sub
Kod 12 Kod ukryty pod przyciskiem Show Status
Zwróćcie uwagę, iż ServiceController musi zostać odświeżony by móc wyświetlić status usługi.
Teraz, gdy zakładka pierwsza jest już oprogramowana, pora stworzyć i oprogramować zakładkę drugą, która wygląda tak jak pokazano na rysunku 9.

Rys. 9 Druga zakładka
Przycisk Get Services wyświetla wszystkie zainstalowane usługi w systemie na niżej umieszczonej kontrolce ListBox.
Private Sub cmdGetServices_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdGetServices.Click lstServices.Items.Clear() Dim controller As New System.ServiceProcess.ServiceController Dim services() As System.ServiceProcess.ServiceController Dim i As Integer services = controller.GetServices() For i = 0 To services.Length - 1 lstServices.Items.Add(services(i).DisplayName) Next End Sub
Kod 13 Pobranie listy zainstalowanych usług w systemie
Metoda GetServices() klasy ServiceController zwraca listę wszystkich zainstalowanych usług w systemie za pomocą tablicy elementów, która potem zostaje przypisana do kontrolki ListBox. By uruchomić, zatrzymać lub za pauzować dowolną usługę w systemie, wystarczy przekazać jej nazwę do odpowiedniej metody (Start(), Stop(), Pause()) klasy ServiceController.
Private Sub cmdStart2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdStart2.Click Dim controller As New System.ServiceProcess.ServiceController(lstServices.SelectedItem) controller.Start() Displaystatus(lstServices.SelectedItem) End Sub Private Sub cmdPause2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdPause2.Click Dim controller As New System.ServiceProcess.ServiceController(lstServices.SelectedItem) If controller.CanPauseAndContinue Then controller.Pause() Displaystatus(lstServices.SelectedItem) Else MsgBox("Service cannot be paused") End If End Sub Private Sub cmdStop2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdStop2.Click Dim controller As New System.ServiceProcess.ServiceController(lstServices.SelectedItem) If controller.Status <> ServiceProcess.ServiceControllerStatus.Stopped Then controller.Stop() Displaystatus(lstServices.SelectedItem) End If End Sub
Kod 14 Kod uruchamiający, zatrzymujący i pauzujący wybraną usługę
To już wszystko, teraz wystarczy uruchomić aplikację i ją przetestować. Dla testu można ustawić monitorowanie wszystkich plików (wraz z podkatalogami) w katalogu c:\Test (jeżeli katalog nie istnieje, utworzyć go) a następnie uruchomić usługę za pomocą przycisku Start. Teraz w monitorowanym katalogu należy utworzyć nowy plik tekstowy a następnie go usunąć i zatrzymać usługę monitorowania plików przyciskiem Stop. Utworzony plik logu aplikacji na dysku c:\MonitorLog.log powinien wyglądać mniej więcej tak:
-------------START------------- MonitorowaniePlikow started At 2004-01-31 22:48:13 ------------------------------- 2004-01-31 22:48:19 : Created : File : C:\Test\new text document.txt 2004-01-31 22:48:21 : Deleted : File : C:\Test\new text document.txt ------------------------------- MonitorowaniePlikow stopped At 2004-01-31 22:48:25 --------------END--------------
Kod 15 Zrodlo pliku monitorowania
W kodzie dołączonym do artykułu kontroler usługi monitorowania plików zawiera dodatkowo opcje ukrywania aplikacji w zasobniku systemowym (system tray), dzięki czemu może ona pozostać uruchomiona przez cały czas działania systemu i nie przeszkadza w pracy użytkownikowi.
|