WindowsService Betrouwbaar schedulen
Door Rutger Smit
11 februari 2004
Elke webdeveloper loopt er vroeg of laat wel eens tegen het volgende probleem aan:
je wilt dat elke dag/week/maand/interval een bepaald stuk code uitgevoerd wordt.
Dikwijls is dit nodig om gegevens te im- of exporteren of om andere batch opdrachten
uit te voeren. In deze tutorial gaan we stap voor stap de oplossing voor dit veel
voorkomende probleem maken.
Een Windows Service?
Een beetje systeem spitter kent het wel: het overzichtsscherm met een lijst van
alle services die op de achtergrond op de pc draaien. Een (windows) service is
in principe een programma zonder GUI (Graphical User Interface / Voorkant) die
hard nodig zijn om het hele systeem te laten draaien. Een goed voorbeeld van zon
service is een webserver. De webserver is als service geschreven omdat dit
programma het ook moet doen als er nog niemand op de computer ingelogd is.
Het voordeel van een service om taken te schedulen is dat het dezelfde opdrachten uit kan voeren als een WebForm (aspx pagina) en soms zelfs meer en/of beter.
Aan de slag!
Was het in C++ nog een behoorlijke klus om een soepel draaiende service te bouwen,
in VisualStudio.NET en C# bouw je zonder al te veel moeite een eigen service.
Als we Visual Studio.NET (VS.NET) geopend hebben kiezen we voor New Project en
noemen het nieuwe project SchedulePlus. VS.NET maakt nu een aantal bestanden aan
die we nodig hebben als basis van de service.
Het eerste wat we nu doen is het aanpassen van ServiceName, dit doe je in het
Properties dialog. Daarna klikken we op de link die daar onder staat: Add
Installer. Deze hebben we nodig om de service op een machine te kunnen registreren.
Er komen nu twee items bij: serviceProcessInstaller1 en serviceInstaller1. Van de
eerste passen we het account aan waaronder de service uiteindelijk moet gaan
draaien. In deze tutorial ga ik er van uit dat deze op een Windows 2000 Server
gaat draaien, daarom kiezen we voor het account LocalSystem. Van serviceInstaller1
is het belangrijk dat we StartupType aanpassen. Deze zetten we op Automatic omdat
we natuurlijk wel willen dat de service wordt gestart tijdens het opstarten van de
server.
Als we nu naar de CodeView van Service1.cs gaan dan zien we daar al een hele lap
code staan. Stoor je er niet aan en laat het lekker staan. Alleen in private void
InitializeComponent() zetten we wat extra zaken. We voegen toe:
timer = new Timer(604800000);
timer.Elapsed += new ElapsedEventHandler( this.ServiceTimer_Tick );
Om gebruik te kunnen maken van deze timer moeten we bovenaan de System.Timers
namespace importeren en buiten InitializeComponent wel even de volgende regel
toevoegen:
private Timer timer=null;
De time dient uiteraard wel gestart te worden op het moment dat de service
opgestart wordt. Dit gebeurt in de protected override void OnStart(string[] args)
VS.NET heeft die al voor je aangemaakt. Zet het start command hier in:
this.timer.Start();
De eerste regel is een nieuwe ServiceController en de tweede en derde regel maakt
een nieuwe time aan. In deze tutorial ga ik er van uit dat we één keer per week
een bepaalde method aan willen roepen die het een en ander voor ons doet. Het
getal 604800000 staat voor precies 1 week. De parameter van het Timer object wordt
uitgedrukt in milliseconden. Op de laatste regel wordt een event aan het time
object toegevoegd. Het Elapsed event wordt uitgevoerd op het moment dat de timer
volledig afgeteld heeft (als hij dus op 0 staat). De method die dan uitgevoerd
wordt heet ServiceTime_Tick en die ziet er alsvolgt uit:
private void ServiceTimer_Tick(object sender, System.Timers.ElapsedEventArgs e)
{
WriteLog("Starting tasks");
RunTasks();
}
Wat er in deze method gebeurt is heel simpel. Elke keer als de timer op 0 komt te
staan dan voert hij de method RunTasks uit. In deze method kunnen we allerlei
opdrachten uitvoeren die we normaliter in een asp(x) pagina uit zouden laten
voeren.
De method WriteLog heb ik er aan toegevoegd om te loggen wat mijn service zoals
doet. Het vraagt één argument en dat is een string, een bericht dat je wilt loggen.
De WriteLog method ziet er als volgt uit:
public void WriteLog(string logtxt)
{
StreamWriter logger = File.AppendText("C:\\servicelog.txt");
logger.WriteLine("{0} {1}\t{2}",DateTime.Now.ToLongTimeString(),DateTime.Now.ToShortDateString(),logtxt);
logger.Close();
}
Als we dit project nu gaan compilen en het niet met errors komt dan heben we in
de, afhankelijk van je instellingen, in de dir Debug een SchedulePlus.exe staan.
Aan te raden is om tijdens het ontwikkelen onder de Debug configuratie te compilen
en indien alles goed werkt VS.NET op Release te zetten. De SchedulePlus.exe zal
dan uiteraard in de dir Release staan.
Het programma installeren
Het installeren van de executable doen we vanaf de VS.NET command prompt
(start > Programs > Microsoft Visual Studio .NET > Visual Studio .NET Tools >
Visual Studio .NET Command Prompt)
Typ op de commandline de volgende opdracht: installutil D:\Pad\Naar\Project\bin\Debug\SchedulePlus.exe
Om een geïnstalleerde service te uninstallen gebruik je switch /u (wel eerst
service stoppen)
D:\Pad\Naar\Project\bin\Debug\SchedulePlus.exe /u
Er komt nu een boel info langs en binnen een seconde is de service op de computer
geïnstalleerd. Open nu je Services window en zie daar:
Omdat we de service zojuist geïnstalleerd hebben moeten we hem de eerste keer
nog even een zetje geven, maar de volgende keer als de pc opstart dan zal de
SchedulePlus service automatisch opstarten. Op het moment dat je de service
opnieuw wilt compilen dien je wel eerst de service te stoppen. Dit is nodig
omdat zolang de service gestart (op gepauzeerd) is, de SchedulePlus.exe in gebruik
is en dus niet overschreven kan worden door de compiler.
NB: de code die je in RunTasks() kunt zetten behandel ik niet in deze tutorial
maar in principe kun je hier al je acties kwijt die je wilt uitvoeren. Dit kan
varieren van het runnen van een stored procedure tot het opvragen van een url
dmv een HttpWebRequest.
|