SERVIZIO - Intercettare cambiamenti in una procedura

martedì 30 dicembre 2008 - 20.03

perla0279 Profilo | Senior Member

Ciao
stò creando un servizio che dovrebbe essere installato su un server....
praticamente dovrebbe andare a controllare una storeprocedure in un database e se dovesse trovare nella colonna stato il valore 1 esegue una serie di scritture su disco di alcuni file.

I pezzi sono già tutti fatti mi manca la parte di monitoraggio store procedure....

Il servizio era già esistente ma prima controllavo i file all'interno di una cartella:
Imports System.Configuration.Install
Imports System.ServiceProcess
Imports System.ComponentModel
Imports System
Imports System.IO
Imports System.Text
Imports System.Collections

Imports System.Reflection
Imports System.Security.Permissions

Public Class PowerStoreSentinel


Private worker As New Worker()


Protected Overrides Sub OnStart(ByVal args() As String)
Dim wt As System.Threading.Thread
Dim ts As System.Threading.ThreadStart
ts = AddressOf worker.Watch
wt = New System.Threading.Thread(ts)
worker.thHandler = wt
wt.Start()
End Sub

Protected Overrides Sub OnStop()
worker.StopService = True
End Sub
End Class

Public Class Worker
Public thHandler As System.Threading.Thread
Public watchfolder As FileSystemWatcher
Public filename As String
Public Percorso1 As String ' percorso identificato in fase di installazione come cartella del servizio
Dim PercorsoInizio As String 'percorso preso dal file config (percorso fisico della cartella del progra)
Public objDB As System.Data.OleDb.OleDbConnection
Public StopService As Boolean

Dim FileLog As String
Dim FSW As System.IO.FileSystemWatcher
Dim myLog As New EventLog
Dim ds As New Data.DataSet

Public Sub Watch()

Dim percorsox As String
Dim percorsoy As String
' INDICARE IL PERCORSO DOVE INSERIRO' IL FILE
'prendo i dati dal web config esistente in modo da poter apportare modifiche eventualmente
If File.Exists(Path.GetFullPath(Percorso1) + "Rss.xml") Then
ds.ReadXml(Path.GetFullPath(Percorso1) + "Rss.xml")
percorsox = ds.Tables("Start").Rows(0).Item("ConfigFileName")
Percorso1 = ""
Percorso1 = percorsox
End If


'*********************************************************************************
filename = Path.GetFullPath(Percorso1) + "Sentinel\ImportaDati\" 'cartella di monitoraggio
FSW = New System.IO.FileSystemWatcher()
FSW.Path = filename
FSW.IncludeSubdirectories = False
FSW.NotifyFilter = (NotifyFilters.LastAccess Or NotifyFilters.LastWrite Or NotifyFilters.FileName)
FSW.Filter = "*.*"
FSW.EnableRaisingEvents = True
AddHandler FSW.Created, AddressOf OnCreated 'evento da monitorare
StopService = False
Do While StopService = False
Thread.Sleep(200)
Loop
End Sub

Private Sub OnCreated(ByVal sender As Object, ByVal e As IO.FileSystemEventArgs)
RicercaPercorso()
Dim PercorsoFile As String
Dim TipoCambiamento As String
PercorsoFile = e.FullPath 'Assegna il percorso del file o directory
TipoCambiamento = e.ChangeType.ToString 'Assegna il tipo di cambiamento

InvioDati(PercorsoFile, TipoCambiamento)

End Sub


Adesso nel Watch () devo richiamare la store procedure e fare il controllo......

Cosa devo usare ?
Ho un pò di confusione sulla creazione di questo tipo di eventi ....

rossimarko Profilo | Guru

Ciao,

per richiamare una stored procedure con ado.net trovi un esempio qui: http://support.microsoft.com/kb/306574

Guarda il punto 4 ("Call the stored procedure in the Click event of the btnGetAuthors button") e vedrai i vari passaggi da fare, con creazione della sqlconnection, del command, del dataadapter ecc

Un altro esempio lo trovi qui: http://www.macronimous.com/resources/calling_stored_procedures_from_ASP.NET_and_VB.NET.asp
-----------------------------------------
Rossi Marco
http://blogs.dotnethell.it/rossimarko

perla0279 Profilo | Senior Member

Il mio problma è che non posso usare button perchè è un servizio di windows quindi non ho le stesse classi per richiamare gli eventi.

Avrei bisogno di un suggerimento sulla classe da usare come evento per far si che parta in automatico ad una determinata ora di sistema.

rossimarko Profilo | Guru

Scusami, non avevo capito.

Nel tuo caso allora direi che devi utilizzare l'oggetto timer (http://msdn.microsoft.com/it-it/library/system.timers.timer.aspx) che scatena l'evento Elapsed ogni xx millisecondi.

Lo dichiari a livello di servizio e poi nell'evento onstart agganci l'evento, imposti l'intervallo e lo abiliti (una volta abilitato parte in automatico).
Nel metodo in cui intercetti l'evento devi:
- disattivare il timer (così non si accavallano chiamate successive)
- eseguire le tue operazioni
- riabilitare il timer per far ripartire gli eventi futuri.





-----------------------------------------
Rossi Marco
http://blogs.dotnethell.it/rossimarko

perla0279 Profilo | Senior Member

sono andata avanti...... in teoria è quasi finito

Public Class PowerStoreSentinel

Private worker As New Worker()

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.
Dim wt As System.Threading.Thread
Dim ts As System.Threading.ThreadStart
ts = AddressOf worker.Watch
wt = New System.Threading.Thread(ts)
worker.thHandler = wt
wt.Start()
End Sub

Protected Overrides Sub OnStop()
' Add code here to perform any tear-down necessary to stop your service.
worker.StopService = True
End Sub



End Class

Public Class Worker
Public thHandler As System.Threading.Thread
Public watchfolder As FileSystemWatcher
Public filename As String
Public Percorso1 As String ' percorso identificato in fase di installazione come cartella del servizio
Dim PercorsoInizio As String 'percorso preso dal file config (percorso fisico della cartella del progra)
Public objDB As System.Data.SqlClient.SqlConnection
Public StopService As Boolean

Dim FileLog As String
Dim FSW As System.IO.FileSystemWatcher
Dim myLog As New EventLog
Dim ds As New Data.DataSet


Public Sub Watch()
Dim percorsox As String

' INDICARE IL PERCORSO DOVE INSERIRO' IL FILE
'prendo i dati dal web config esistente in modo da poter apportare modifiche eventualmente
If File.Exists("C:\Servizi\Artistic.xml") Then
ds.ReadXml("C:\Servizi\Artistic.xml")
percorsox = ds.Tables("inizio").Rows(0).Item("ConfigFileName")
Percorso1 = ""
Percorso1 = percorsox
End If

cercadati()
StopService = False
Do While StopService = False
Thread.Sleep(200)
Loop
End Sub

Private Sub cercadati()
Dim CodPag As String
CodPag = "001"
Dim sql As String = "xxxxxxxxxxx select di ricerca"
Dim objCommand As New SqlCommand(sql, objDB)
Dim objReader As SqlDataReader = objCommand.ExecuteReader()

If objReader Then
Exit Sub
Else
EliminaNodoXml("0", "XMLfile1", "item", "channel")
inseriscinuovinodi(objReader, "XMLfile1", "item", "channel")
End If
End Sub
End Class


Non riesco a farlo partire quindi presuppongo ci siano degli errori............
Il servizio non parte (per farlo partire uso i comandi dos)....... in Visualizzazione di eventi mi dà questo errore
'Impossibile avviare il servizio. Il processo di servizio non ha potuto connettersi al controller di servizio

Per ulteriori informazioni, consultare la Guida in linea e supporto tecnico all'indirizzo http://go.microsoft.com/fwlink/events.asp.'

Non so come procedere.........

rossimarko Profilo | Guru

Il servizio è stato installato tra i servizi di windows? Quando lo fai partire ti riferisci alla console dei servizi di windows oppure a visual studio?

Intanto ti giro due righe di codice su come fare un servizio che parta ad una determinata ora, giusto per darti un'idea:

Public Class MioServizio Private TimerTask As System.Timers.Timer = Nothing Private _LastRun as Datetime = DateTime.MinValue Public Sub New() ' This call is required by the Windows Form Designer. InitializeComponent() End Sub Protected Overrides Sub OnStart(ByVal args() As String) TimerTask = New System.Timers.Timer() TimerTask.Interval = 60000 'Intervallo in millisencondi, quindi equivale ad 1 minuto AddHandler TimerTask.Elapsed, AddressOf TimerTask_Elapsed 'Avvia timer TimerTask.Start() ' ---------- FINE TIMER --------------- End Sub ''' <summary> ''' Intercettato evento del timer ''' </summary> Private Sub TimerTask_Elapsed(ByVal sender As Object, ByVal e As Timers.ElapsedEventArgs) TimerTask.Stop() Try ' Esecuzione alle ore 10 if DateTime.Now.Hour = 10 AndAlso _LastRun.Date <> DateTime.Now.Date Then _LastRun = DateTime.Now 'Esegue operazioni del servizio RunTasks() End IF Catch ex As Exception 'Scrivo dati in un log Finally TimerTask.Start() End Try End Sub ''' <summary> ''' Esegue i task programmati ''' </summary> Private Sub RunTasks() 'Qui puoi inserire il codice che dovrà gestire il tuo servizio End Sub Protected Overrides Sub OnStop() 'Stoppa timer TimerTask.Stop() End Sub End Class


-----------------------------------------
Rossi Marco
http://blogs.dotnethell.it/rossimarko

perla0279 Profilo | Senior Member

intanto grazie..... cosi sono riuscita ad inserire anche il timer :-)
che proprio non capivo...

Mi spiego meglio perchè ho riprovato ma comunque non va-----

Io compilo il progetto poi vado su debug e faccio partire il .exe creato con i comandi dos
sc start sentinel

Poi vado sulla consol servizi di windows e mi accorgo che il servizio non è partito.... ????
Tra i servizzi di Visual Studio (su attach) trovo un PWsentinel che è il nome del progetto ma non trovo Sentinel che dovrebbe essere il nome del servizio ????
Comunque non riesco ad attacarmi....

Poi per vedere cosa è sucesso.... o almeno per provare a capire cosa succede sono andata su visualizzatore di eventi in windows è su applicazioni mi da questo errore:
"Impossibile avviare il servizio. Il processo di servizio non ha potuto connettersi al controller di servizio

Per ulteriori informazioni, consultare la Guida in linea e supporto tecnico all'indirizzo http://go.microsoft.com/fwlink/events.asp."

??????????? dove sbaglio

rossimarko Profilo | Guru

Prova a verificare nelle impostazioni del progetto ( sezione application ) che lo StartUp object sia la classe del tuo servizio oppure la "sub main". Nel secondo caso verifica che la "sub main" faccia effettivamente partire il servizio.
Un'altra verifica che puoi fare è quella di inserire nell'onstart una procedura che salva un file di testo, tanto per capire se passa di li o meno.

Una domanda, come hai installato il servizio? Attraverso l'utility installutil (http://msdn.microsoft.com/it-it/library/50614e95.aspx) ?
-----------------------------------------
Rossi Marco
http://blogs.dotnethell.it/rossimarko

perla0279 Profilo | Senior Member

Ciao
ho riprovato a crearlo stando attenta a quello che facevo.... in modo da capire eventuali errori..........

- Ho creato un progetto con visual studio 2008 'Service'
- L'ho chiamato Prova (un nome fittizio per provare)
- Ho scritto questo codice semplice semplice tanto per vedere se funzionava:

Imports System.IO
Imports System.Text
Imports System.Reflection
Imports System.Security.Permissions
Imports System.Threading

Public Class Artistic
Private worker As New Worker()

Protected Overrides Sub OnStart(ByVal args() As String)

Dim wt As System.Threading.Thread
Dim ts As System.Threading.ThreadStart
ts = AddressOf worker.Watch
wt = New System.Threading.Thread(ts)
worker.thHandler = wt
wt.Start()
End Sub

Protected Overrides Sub OnStop()
worker.StopService = True
End Sub
End Class

Public Class Worker
Public thHandler As System.Threading.Thread
Public watchfolder As FileSystemWatcher
Public filename As String
Public Percorso1 As String
Dim PercorsoInizio As String

Public objDB As System.Data.OleDb.OleDbConnection
Public StopService As Boolean

Dim FileLog As String
Dim FSW As System.IO.FileSystemWatcher
Dim myLog As New EventLog
Dim ds As New Data.DataSet

Public Sub Watch()
Dim FileLog As String
FileLog = "C:\Programmi\prova.txt"
Dim objStreamWriter As StreamWriter
objStreamWriter = New StreamWriter(FileLog, True)
objStreamWriter.WriteLine("Error")
objStreamWriter.Close()


StopService = False
Do While StopService = False
Thread.Sleep(200)
Loop
End Sub

End Class

- Ho fatto partire il debug, che ha generato la cartella bin con dentro debug ed i relativi file.

- Poi ho creato un file .bak
con il seguente comando dentro in modo che mi faccia partire il servizio da riga di comando:

sc create Prova binPath= F:\prova\bin\Debug\prova.exe
sc start prova

- Poi sono andata a controllare ma nei servizi non c'è traccia di questo ???
Anche da visual studio se faccio Attach, per attacarmi al processo non lo trovo sull'elenco.......

Adesso a me il procedimento sembra coretto....... non riesco a capire perchè il servizio non parta ma soprattutto perchè non mi segnala nessun errore.....

Tempo fà per lavoro nè ho creato un altro e mi ricordo che mi segnalava comunque gli errori che trovava nello Start... ??'

rossimarko Profilo | Guru

Per fare l'installazione usa installutil, io di solito faccio due file bat, Install e Uninstall che inserisco nel progetto e copio nella bin quando mi serve.
All'interno del file bat di installazione inserisco:
%systemroot%\Microsoft.NET\Framework\v2.0.50727\installutil NomeDelFileExe.exe
pause

mentre per l'uninstall:
%systemroot%\Microsoft.NET\Framework\v2.0.50727\installutil /u NomeDelFileExe.exe
pause

Un'altra cosa che ti suggerisco di fare è quella di usare come struttura l'esempio di servizio che gestisce il timer che ti ho riportato prima. Non hai bisogno di avviare dei thread nell'onstart, ma semplicemente devi schedulare il timer perchè generi un evento ogni xx millisecondi e all'interno di questo eventi controlli se l'ora corrente è quella in cui deve girare.
-----------------------------------------
Rossi Marco
http://blogs.dotnethell.it/rossimarko

perla0279 Profilo | Senior Member

non mi sono ancora data per vinta :-)

Allora ho cambiato il codice:
Imports System.IO
Imports System.Text
Imports System.Reflection
Imports System.Security.Permissions
Imports System.Threading

Public Class Artistic
Private TimerTask As System.Timers.Timer = Nothing
Private _LastRun As DateTime = DateTime.MinValue

Public Sub New()

' This call is required by the Windows Form Designer.
InitializeComponent()

End Sub


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.
TimerTask = New System.Timers.Timer()
TimerTask.Interval = 60000 'Intervallo in millisencondi, quindi equivale ad 1 minuto

AddHandler TimerTask.Elapsed, AddressOf TimerTask_Elapsed

'Avvia timer
TimerTask.Start()

'Dim FileLog As String
'FileLog = "c:\prova.txt"
'' Write(FileLog, "Error")
'Dim objStreamWriter As StreamWriter
'objStreamWriter = New StreamWriter(FileLog, True)
'objStreamWriter.WriteLine("Error")
'objStreamWriter.Close()
End Sub


Private Sub TimerTask_Elapsed(ByVal sender As Object, ByVal e As Timers.ElapsedEventArgs)

TimerTask.Stop()

Try
' Esecuzione alle ore 10
If DateTime.Now.Hour = 3 AndAlso _LastRun.Date <> DateTime.Now.Date Then
_LastRun = DateTime.Now

'Esegue operazioni del servizio
RunTasks()
End If
Catch ex As Exception
'Scrivo dati in un log
Finally
TimerTask.Start()
End Try

End Sub

''' <summary>
''' Esegue i task programmati
''' </summary>
Private Sub RunTasks()

Dim FileLog As String
FileLog = "c:\prova.txt"
' Write(FileLog, "Error")
Dim objStreamWriter As StreamWriter
objStreamWriter = New StreamWriter(FileLog, True)
objStreamWriter.WriteLine("Error")
objStreamWriter.Close()

End Sub

Protected Overrides Sub OnStop()

'Stoppa timer
TimerTask.Stop()

End Sub


Poi ho fatto i due file bat, su quello di installazione ho scritto questo codice:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe Artistic.exe
pause

Poi lo fatto partire su una macchina virtuale (pensavo che magari la mia avendo un sacco di cose installate potesse bloccare il servizio in qualche modo)

Il visualizzatore di eventi mi torna questi due messaggi di errore:
Il time provider NtpClient non è in grado di individuare alcun controller di dominio da utilizzare quale origine dell'ora. NtpClient ritenterà fra 30 minuti.

Il time provider NtpClient è configurato per acquisire l'ora da una o più origini dell'ora, ma nessuna origine dell'ora è accessibile attualmente e non verrà eseguito alcun tentativo di contattare un'origine per 29 minuti. NtpClient non dispone di alcuna origine di ora esatta.



VI PREGO NON ABBANDONATEMI PROPRIO ADESSO ............ voglio riuscire a farlo stò servizio :-)

rossimarko Profilo | Guru

In questo caso non dipende dal tuo servizio, ma da degli errori dovuti al servizio di sincronizzazione del tempo di windows. Fai una prova mettendolo con avvio manuale e stoppandolo.
Il servizio si chiama windows time

Altre info le trovi qui: http://social.technet.microsoft.com/Forums/en-US/winserverDS/thread/c9d0f1a7-4b01-4a0c-b6b6-e8e86dbfd3ce/
-----------------------------------------
Rossi Marco
http://blogs.dotnethell.it/rossimarko
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5