Introduction
As we all know, sometimes we have the necessity of running tasks at predefined times. Windows has "Schedule tasks", and they are very useful and reliable. However, I always find myself grinding my teeth when using them because I don't want to make a script or command line for every little thing. And that is where the Windows services get into action...
However, I don't like depending on "installutil.exe" to install and uninstall services. I would rather have it standalone. So I got my requirements together and set to work on a code base that I could use as a Windows service.
This code is that code base I use every time I need a new service. I just copy the solution, and change its name. Instant service!
What This Gives Me?
- Multiple threads configured on the app.config
- Individual log files for each thread (errors and messages)
- Possibility of sending errors by mail
- In debug (under Visual Studio or not), runs as console application
- In Release, runs as Service
- It can run as Console Application in release mode when started with "
-c
" switch - Self Install and uninstall, avoiding external tools
Examples
Here's an example of the output:
*******************************************************************************
XWega Service Base V:1.0.0.1
===============================================================================
WARNING: this is a debug version
===============================================================================
-------------------------------------------------------------------------------
29-08-2010 20:30:51.2964 => SVR : Service Started (Debug)
29-08-2010 20:30:51.3214 => Thread1 : STARTING...
29-08-2010 20:30:51.3214 => Thread1 : do your stuff
29-08-2010 20:30:51.3264 => Thread1 : ...DONE!
The possible command switch (shown by "-h
"):
*******************************************************************************
XWega Service Base V:1.0.0.1
===============================================================================
HELP:
-c : Run as console application
-i : Install service
-u : Uninstall service
Example of the app.config
<appThreads enabled="true" abortTimeout="00:10:00">
<thread enabled="true" runOnStart="true" recurse="true" time="00:00:10"
name="ThreadThatDoSomething" method="Thread1.GO" workingFolder="" />
<thread enabled="true" runOnStart="true" recurse="true" time="00:01:00"
name="ThreadThatTrys" method="Thread2.GO" workingFolder="" />
<thread enabled="true" runOnStart="true" recurse="false" time="01:00:00"
name="ThreadThatBeleive" method="Thread3.GO" workingFolder="" />
</appThreads>
Example Cases
- If you want to run a task every 5 minutes, you would set it like:
recurse="true" time="00:05:00"
- If you want to run a task at 12am everyday, you would set it like:
recurse="false" time="12:00:00"
It's possible to have the same piece of code run has two (or more) threads, if you configure like this:
one thread with name="ThreadThatTrys" method="ThreadCode.GO"
and other with name="ThreadThatTrysAgain" method="ThreadCode.GO"
You give them different names, but give them the same method. In this case, take into consideration that you may have to sync the access to the used resources.
Notes on the Thread Configuration
enable
: Self explanatory runonstart
: If true
, the thread will run when the service is started, if false
, it will wait for the designated time to run recurse
: If true
, the time value will be the wait period between the thread exits and get started again. If false
, time is an absolute value indicating the time of day for the thread to run. The same Thread
will never start if the previous run has not ended yet. name
: Name of the thread
, this will be used to give a name to the log files, and identify the error mails. method
: The C# method that will be started, and that receives the AppThreadStruct
representing the thread workingFolder
: This is accessible in the AppThreadStruct
and can be used to provide the thread with a disk or network path where it should take care of its business.
One Thread has the Following Base Template
using System;
using System.Threading;
using XwServiceBaseSrv;
class Thread1
{
public void GO(AppThreadStruct thread)
{
try
{
Srv.LogThread(LogLevel.Debug1, thread.Settings, "STARTING...", null, false);
Srv.LogThread(LogLevel.Debug1, thread.Settings, "...DONE!", null, false);
}
catch (Exception ex)
{
Srv.LogThread(LogLevel.Error, thread.Settings, "GO", ex, false);
}
}
}
The AppThreadStruct
has some useful properties, but I will highlight “StopRequest
”.
“StopRequest
” will be signalled if the service is asked to stop, so this is extremely important to check inside your long cycles in order to break out of them. If you don’t, you will end up with a service that takes ages to stop and you will find yourself using Task Manager to kill the service unnecessarily.
Using the Project
As I mentioned before, when I want to create a new service, I just copy the project, and rename it. Not a glamorous solution, but it works. I rename the solution and project files, open them with a text editor and rename the appropriate string
s. Very easy as you most certainly know.
There are however some strings on the code itself that you must change, and those are the ones that identify the service to the “Windows service manager”. You will find these string
s close to the beginning of file Service.cs:
static string sServiceName = "XwServiceBase";
static string sServiceDisplayName = "XWega Service Base";
static string sServiceDescription =
"Generic service to use has template for Windows Services";
Future Updates
- Any future big releases will be updated on CodeProject
- Any future small updates will be at XWega Tools
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.