.NET Windows Service Template using Timer, Topshelf and Log4Net

Published on
4,431 Points
1 Endorsement
Last Modified:
Shaun Vermaak
My name is Shaun Vermaak and I have always been fascinated with technology and how we use it to enhance our lives and business.
I have personally never liked the standard Windows Service template that comes with Visual Studio. This article describes how I created a Visual Studio template build on the Topshelf library that I use to develop stable Windows Services.


What I like about Topshelf is that it turns a console application into a service installer with a comprehensive set of command-line options for installing, configuring, and running your application as a service. This means you can run it as a console application and easily install it as a service without having to write the code.

I also utilize the Topshelf.Log4Net to enable both service and application logging.

For your convenience, the Visual Studio template can be downloaded from http://blog.ittelligence.com/wp-content/uploads/2018/12/ITtelligence-Windows-Service.zip and simply imported

Creating the template

1) Start Visual Studio and create a Console Application (.NET Framework) Project

2) From Package Manage Console run this command to install Topshelf

Install-Package Topshelf -Version 4.1.0

3) From Package Manage Console run this command to install Log4Net for Topshelf

4) Add a class and call it MyService.cs

5) Add the following code to Service.cs (See comments in the code to understand what it is doing)

Application specific code can be added to the OnTimedEvent method.

using log4net;
using log4net.Config;
using System;
using System.Timers;

namespace WindowsServiceTemplate
public class MyService
// Setup log4net logger
private static readonly ILog _log = LogManager.GetLogger(typeof(MyService));

// The timer that triggers the event
private Timer _heartbeatTimer = new Timer();

// Boolean to determine if trigger should reoccur
private volatile bool _requestServiceStop = false;

// Interval that event should be triggered at
private readonly long _heartbeatInterval = 10;

public MyService()
// Configure log4net from app.config file
// Set the timer interval
_heartbeatTimer.Interval = _heartbeatInterval * 1000;
// Set the event that should be triggered
_heartbeatTimer.Elapsed += OnTimedEvent;
// Important! We do not want the event to reoccur unless on trigger has finished
_heartbeatTimer.AutoReset = false;
// Start event

public void Start()
// Event should not stop the timer
_requestServiceStop = false;
// Start event

public void Stop()
// Event should stop the timer
_requestServiceStop = true;
// Stop event

private void OnTimedEvent(object source, ElapsedEventArgs e)
// Log heartbeat message

// Put code here

// Start timer again if no request to stop recieved
if (!_requestServiceStop)

6) Add a class and call it ConfigureService.cs

7) Add the following code to ConfigureService.cs (See comments in the code to understand what it is doing)

using log4net.Config;
using Topshelf;

namespace WindowsServiceTemplate
internal static class ConfigureService
internal static void Configure()
// Configure log4net from app.config file

// Service configuration
HostFactory.Run(configure =>
configure.Service<MyService>(service =>
service.ConstructUsing(s => new MyService());
service.WhenStarted(s => s.Start());
service.WhenStopped(s => s.Stop());

// Set account that window service use to run.

// Set service to the log4net

// Service text
configure.SetServiceName("Put your service name here");
configure.SetDisplayName("Put your service display name here");
configure.SetDescription("Put your service description here");

8) Edit the App.config file. Essentially we are adding the Log4Net configuration 

<?xml version="1.0" encoding="utf-8"?>

<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />

<appender name="console" type="log4net.Appender.ConsoleAppender, log4net">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d{ABSOLUTE} [%thread] %-5p %c{1}:%L - %m%n" />

<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<file value="logs\" />
<datePattern value="'Service-Name-'dd.MM.yyyy'.log'" />
<staticLogFileName value="false" />
<appendToFile value="true" />
<rollingStyle value="Composite" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="5MB" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d [%t] %-5p %c - %m%n" />

<level value="DEBUG" />
<appender-ref ref="console" />
<appender-ref ref="RollingFile" />

9) Finally, edit Program.cs

namespace WindowsServiceTemplate
internal class Program
private static void Main(string[] args)
// Start Windows Service

Demo Execution

This is demo execution of application directly from command line.

The following shows a sample of the log file that is generated

The application can easily be installed as a Windows Service with the INSTALL parameter

The installed service


I hope you found this tutorial useful. You are encouraged to ask questions, report any bugs or make any other comments about it below.


Note: If you need further "Support" about this topic, please consider using the Ask a Question feature of Experts Exchange. I monitor questions asked and would be pleased to provide any additional support required in questions asked in this manner, along with other EE experts...  


Please do not forget to press the "Thumbs Up" button if you think this article was helpful and valuable for EE members.

It also provides me with positive feedback. Thank you!

Ask questions about what you read
If you have a question about something within an article, you can receive help directly from the article author. Experts Exchange article authors are available to answer questions and further the discussion.
Get 7 days free