Click here to Skip to main content
Click here to Skip to main content
Go to top

Base Library for Multi-threaded Windows Services

, 2 Jun 2010
Rate this:
Please Sign up or sign in to vote.
This is a base library for multi-threaded Windows Services. It manages starting and stopping services, and defines the base structure.


This is a base library for multi-threaded Windows Services. It manages starting and stopping services and defines a base structure.

Library Description



There are three interfaces in the library:

  • IConfigurable defines the interface for the classes which can be configured.
  • IRunnable defines the interface for classes that have a determined lifetime for execution.
  • IService defines the interface for service classes.

ServiceManager Class


This class is the main class in the library, and manages the starting and stopping of services configured in the system. This class implements the Singleton Design Pattern.

ServiceSkeleton Class


This is the base of all service classes. All service classes must implement this class.

How it Works

The entry point is the ServiceManager class.

The first step is defining the service classes to the ServiceManager.

ServiceManager.SingleInstance.Services = new List<IService>
    new WeatherService(),
    new CurrencyService(),
    new BackupService(),
    new StatusChecker()

The second step is signaling ServiceManager to begin the configuration process.


The third step is signaling ServiceManager to start the configured services.


Designing a Service Class

All service classes must implement the ServiceSkeleton class.

public class WeatherService : ServiceSkeleton

After this, three abstract methods must be implemented too.

  • SleepTime
  • ExecuteInternal
  • ConfigureInternal

When execution time comes, the skeleton class calls the ExecuteInternal method. After work is done, the skeleton class sleeps for SleepTime seconds.

For example, a service which gets currency from a website:

using System;
using System.Net;
using ServiceManagerBase;

namespace MyCompany.MyProject.Services
    public class CurrencyService : ServiceSkeleton
        private string _currencyUrl;

        #region Overrides of ServiceSkeleton

        public override int SleepTime()
            return 60*5; // sleep for 5 minutes

        public override void ExecuteInternal()
                Log.Debug(String.Format("Connecting to web site: {0}", _currencyUrl));

                var request = WebRequest.Create(new Uri(_currencyUrl));

            catch (Exception exception)
                Log.Error("Connection failed.", exception);

            // TODO: Rest of the code goes here...

        public override void ConfigureInternal()
            _currencyUrl = "";

            IsConfigured = true;


How to Define a Schedule?

This library is not designed for a schedule operation. But you can schedule jobs. For example:

public override void ExecuteInternal()
    // If time is not 02:00:00, exit

    Log.Debug("Checking if time is 02:00:00");

    if (!(DateTime.Now.Hour == 2 && DateTime.Now.Minute == 0 
                                 && DateTime.Now.Second == 0))
        Log.Debug("Time is not 02:00:00. Exiting.");

    Log.Debug("Time 02:00:00. Starting backup job...");

    // TODO: Do backup job...

Stopping the Service: What to do in Service Classes?

When a service is being stopped, the ServiceManager flags the IsStopRequested boolean field to true. In your code, for example, if you are looping a huge array, you have to control this flag so that the service can stop successfully without error.

Let's say that we have a collection.

var users = GetQueue();

In your code, you loop in this collection. Meanwhile, the service is being stopped. You may choose two of these methods:

In the first method, you handle exiting from the loop process.

foreach (var user in users)
    if (ServiceManager.SingleInstance.IsStopRequested)

    Log.Debug(String.Format("Analysing user ID: {0}", user.UserID));

    // TODO: Analyse...

In the second method, if you're using complex algorithms and if it'll be hard to handle, you can throw an exception.

foreach (var user in users)
    if (ServiceManager.SingleInstance.IsStopRequested)
        throw new StopRequestedException();

    Log.Debug(String.Format("Analysing user ID: {0}", user.UserID));

    // TODO: Analyse...

This exception will be caught by the ServiceSkeleton without any problems.

How to Change the Name of the Log File?

By overriding the GetLoggerName method, you can change the name of the log file.

protected override string GetLoggerName()
    return "Custom logger name";

Base Loop

The base loop in the ServiceSkeleton class is the main loop for every service. It signals the service to execute its own process, manages sleeping, and handles the exceptions.

public void Execute()
    Log.Debug(String.Format("Service \"{0}\" entered the execute loop.", this));

    while (!ServiceManager.SingleInstance.IsStopRequested)
        catch (ThreadAbortException) {}
        catch (StopRequestedException) {}
        catch (Exception ex)
            Log.Error("Error on internal executing process.", ex);

        Log.Debug(String.Format("Sleeping for {0:n0} second(s).", SleepTime()));

        for (var i = 0; i < SleepTime(); i++)

            if (ServiceManager.SingleInstance.IsStopRequested)

    Log.Debug(String.Format("Service \"{0}\" exited from the execute loop.", this));


This is the first published version.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Efe Erdogru
Software Developer (Senior)
Turkey Turkey
No Biography provided
Follow on   Google+

Comments and Discussions

QuestionHow can I restart a managed 'child' service if it stops unexpectedly? Pinmemberjroughgarden22-Jun-12 14:16 
AnswerRe: How can I restart a managed 'child' service if it stops unexpectedly? PinmemberEfe Erdogru19-Mar-13 11:24 
Hi Jeff,
Sorry for late answer. I've missed this comment Frown | :-(
I don't know if you found a solution for your question. By design, manager should never stop unexpectedly because of having a global exception catch mechanism.
I think we have to seperate logics which are service process itself and what the service is doing. We can be sure service will never fail and continues trying its process after the sleep time. But if you want to monitor if service is doing its job well, you may choose several methods. Although when service fails it logs, you can use a logic to mail yourself when error occured. You may want to see other post: SystemWatchdog - An Experimental & Educational Project for System Monitoring[^]
Starting and stopping child services is a good point that this manager can not handle and honestly I never think about it. But at first I can imagine two different ways.
You can define services into a table in a database and one of the child service will responsible for starting and stopping other services. When manager starts, only one child will start. That child reads service list from DB, and then creates service instances. After a period, service reads list from DB again and if any of them is disabled, it'll aborts that service instance. Or you may choose reading from a local TXT or XML file rather than a DB. Good solution? Maybe. Depends on your architecture.
Another way is, opening a, for example TCP/IP local port on application and wait connection via that port to signal rather start or stop a child.
Again, sorry for the late answer.
GeneralMy vote is definitely 5 too!!! Pinmemberevrenyagmur11-Feb-11 1:18 
GeneralMy vote is 5 too PinmemberTefik Becirovic6-Sep-10 0:01 
GeneralRe: My vote is 5 too PinmemberEfe Erdogru6-Sep-10 1:29 
JokeRe: My vote is 5 too PinmemberTefik Becirovic6-Sep-10 1:48 
GeneralMy vote of 5 PinmentorSandeep Mewara28-Aug-10 7:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140916.1 | Last Updated 2 Jun 2010
Article Copyright 2010 by Efe Erdogru
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid