This article discusses how to design and develop a Windows polling service that is flexible enough to allow the addition of new tasks in the future.
There are two main parts in this article, the task configuration and creation and execution of these tasks.
This also makes for a good tutorial on how to setup a custom configuration section using Configuration Section Designer and on using the system timer class to poll in a Windows service.
In an enterprise system environment, you often come across the need to execute asynchronous processes/tasks. The most common approach is to create a Windows service that will poll for tasks and execute them. However, this leads to the creation of a number of services over time.
Managing multiple services and ensuring that they are all up and running can be a huge task by itself. Not to forget the development time involved in rewriting the same polling service code every time. This led me to build a generic polling service that could run any task in an orderly manner and be flexible enough to allow for the addition of new tasks with relative ease in the future.
You will need to download and install the Configuration Section Designer from CodePlex.
Using the Code
This first part describes how to create a configuration section dedicated to configuring tasks. The Configuration Section Designer tool is a nifty little tool that allows you to do much of the heavy lifting easily and I highly recommend it.
First, we need to create a configuration section to deal with configuring the individual tasks.
Once you create your project, you will need to right click on the project in the Solution explorer and click on the Add New Item.
This will bring up the Add New Item dialogue box. For a default installation of Configuration Section Designer tool, you should be able to choose
ConfigurationSectionDesigner template as illustrated below:
Designing the Configuration Section
Once you have the designer open, you will need to create a Configuration Element by dragging the Configuration Element icon from the Toolbox. Right click on the newly created Configuration Element on the designer and choose Properties from the context menu. Then enter the following properties in the same way as creating the Configuration Section above.
Name - Task
NameSpace - WSPolling
Add the following attributes to the
Configuration Element in the same way as creating the Configuration Section above.
* Please note that the XML Name is case sensitive.
|Name ||Type ||Xml Name ||IsKey |
Then we need to add a Configuration Element Collection in much the same way as above you can set the properties for the Configuration Element Collection.
Name - Tasks
Namespace - WSPolling
Xml Item Name - task
Item Type - Task
Then we need to add a Configuration Section from the toolbox. In the same way you defined the properties for the Configuration Element, right click on the newly created configuration section element on the designer and choose Properties from the context menu.
In the Properties window, set the following properties:
Name - TaskConfiguration
Namespace - WSPolling
XML Section Name - taskConfiguration
* Please note that the XML Section Name is case sensitive.
Then you need to create an element under Configuration Section and set the following properties.
Name - Tasks
Type - Tasks
Xml Name tasks
The end result of all the configuration should look like the below illustration:
The following code creates a Windows polling service that loads, sorts and executes the various tasks and their attributes.
ITask – The interface that defines the individual task
TaskManager – The object that loads, sorts and executes the various individual tasks
Task1 - Implementation of the task
Task2 - Implementation of the task
Create a System Timer
We make use of the
System.Timer class to fire events at regular intervals to perform the polling action of the Windows service. You can configure the timer to fire at any given time span - here it is set at 4 secs. First, we instantiate an object of type
TaskManager. Then we load all the enabled tasks by looking up the configuration section in the app.config file.
public void runService()
TaskManager tm = new TaskManager();
aTimer = new System.Timers.Timer(4000);
this.aTimer.AutoReset = true;
aTimer.Elapsed += new ElapsedEventHandler(tm.ExecuteTasks);
This object manages how we load and execute the tasks. This object contains two main methods.
LoadSortedProviders method loads all tasks configured under the config section
TaskSettings and then sorts them by
TaskOrder. You can add any additional behaviour you may require in this method.
public void LoadSortedProviders()
foreach (Task tc in config.Tasks.OfType<Task>())
ITask t = Activator.CreateInstance(Type.GetType(tc.TaskName)) as ITask;
t.TaskOrder = tc.TaskOrder;
t.Enabled = tc.Enabled;
catch (Exception ex)
ExecuteTasks method executes each task from the ordered tasklist.
public void ExecuteTasks(object source, ElapsedEventArgs e)
foreach (ITask t in _cprovider)
catch (Exception ex)
These classes contain the actual task implementation. You can extend the polling service by adding classes that implement the
ITask interface and adding the task implementation within the
Execute method of the
Task class. They also need to be configured in the .config file as detailed in the below Task Configuration section:
public void Execute( )
Every task that is added will require the following configuration to be setup in the config file.
taskName is the fully qualifying name of your
Task object including the namespace, enabled will determine if it is to be run or ignored when the polling service is started,
taskOrder attribute will determine what order the task is executed in. You can add more attributes for your customized requirements.
<task taskName="WSPolling.Task1" enabled="true" taskOrder="0" />
<task taskName="WSPolling.Task2" enabled="true" taskOrder="1" />
Points of Interest
One of the things that I would like to do is try and run these tasks in their own memory space so that they don’t create any dependencies on each other. That is, if any of them does crash, I would like to see the others continue to run.
System.Timer class will execute the event on a thread that is obtained from the