Tutorial – Building a Windows Service application in C#

In this post I will explain how to build a Windows Service application which (for debug purposes) could also be started as a Windows Console application using the .NET Framework 2.0 or higher. The source code of the application can be downloaded here.

During the course of this article we will construct a small application which will leave a message in the Windows Event Log every minute. The application is of course completely useless, however it demonstrates how to construct a Windows Service application which could also be started as a Windows Console application. Leaving messages in the Windows Event Log also makes it easy for us to see if the application is working correctly when running as a Windows Service.

Creating the skeleton of the application

First lets get started to build the project skeleton. Start with opening Visual Studio 2005 (for this article I used Visual Studio 2005; however, everything works the same in Visual Studio 2008). When Visual Studio is started go to ‘File -> New -> Project’ (or press Ctrl+Shift+N). From the right pane in the ‘New Project’ dialog window expand the ‘Visual C#’ project type and select ‘Windows’. Now select de option ‘Windows Service’ and name it “EventLogger” (see screenshot)  and press the ‘OK’ button.

After the project has been created rename the file ‘Service1.cs’ to ‘EventLoggerService.cs’.
The next step is to add an ‘Installer Class’ to the project. The ‘Installer Class’ will be called by the “InstallUtil.exe” tool (which is part of the .NET Framework) to register the application as a Windows Service. The ‘Installer Class’ makes sure that our service is correctly registered as a Windows Service application. The exact implementation of this class will be discussed a bit later. The easiest way to add the ‘Installer Class’ to the project is by opening the ‘EventLoggerService.cs’ file in design view. Now make a right mouse click somewhere in the grey area and choose ‘Add Installer’ from the context menu (see screenshot). You will now see that an ‘Installer Class’ is added to your project.

Now add a new ‘Class’ to the project. This class will hold all the application logic, in this case it will contain the logic to send log messages to the Windows Event Log. The implementation of the class is discussed in the next paragraph called ‘Implementing the application logic’. You can add the new class by taking the following steps. In the Solution Explorer right click on the project name “EventLogger” and select the option “Add” -> “Class…”. In the “Add New Item” dialog window name the new class “EventLoggerApp.cs” (see screenshot) and hit the “Add” button.

The last step in creating the skeleton is adding a “Install.cmd” and a “Uninstall.cmd” file to the project. These files will contain simple batch scripts to respectively install and uninstall our application as a Windows Service. The scripts will utilize the “InstallUtil.exe” tool to accomplish this task. The implementation of these scripts are discussed in the paragraph “Creating the ‘Install.cmd’ and ‘Uninstall.cmd’ batch scripts”. Adding the “Install.cmd” and “Uninstall.cmd” files can be done in the following manner. In the Solution Explorer right click on the project name ‘EventLogger’ and select the option “Add” -> “New Item…”. In the ‘Add New Item’ dialog window choose the ‘Text File’ template and name it “Install.cmd” (see screenshot) and hit the ‘Add’ button. Adding the “Uninstall.cmd” file can be done in the same way, only name it “Uninstall.cmd”.

When all the above files are added the skeleton is setup and we are ready to start implementing the application. In the next paragraph I will discuss the implementation of the application logic, and after that we can focus completely on the setting up the Windows Service application.

Implementing the application logic

As mentioned earlier we will implement the application logic in the class file “EventLoggerApp.cs”. In this file we will write code which each minute sends a message to the Windows Event Log. We will put the application logic into a separate class to make sure that the Windows Service (represented by the “EventLoggerService.cs” class) and the Console Application (which will be started by the logic in the “Program.cs” file) execute the exact same code.

To realize this we will create the following methods in the “EventLoggerApp.cs” class:

Method Description
Private
Execute() This method shall be run on a separate thread and will be called by the Start() method.

This method will make sure that each minute a message is send to the Windows Event Log.

Public
Start() This method is used to start the application. This method will be called from the OnStart() event handler of the “EventLoggerService” class or at the moment the Console Application is started.

The Start() method will start a new thread which will run the Execute() method.

Stop() This method is used to stop the application. This method is called from the OnStop() event handler of the “EventLoggerService” class or at the moment the Console Application is stopped.

The Stop() method will send an abort signal to the thread running the application logic (inside the Execute() method) and will return, showing the application is stopped.

Each method and its implementation are described in the following paragraphs.

Execute method

The ‘Execute’ method is responsible for running the application logic, in this case sending a message to the Windows Event Log each minute. The code for the ‘Execute’ method is very straightforward and is given below.

private void Execute()
{
  // Loop until the thread gets aborted
  try
  {
    while (true)
    {
      // Write the current time to the eventlog
      _log.WriteEntry(string.Format("INFO (EventLoggerApp.Execute): Current
        time is: {0}.",   DateTime.Now.ToString("HH:mm:ss")));
 
      // Sleep for one minute
      Thread.Sleep(60000);
    }
  }
  catch (ThreadAbortException)
  {
    _log.WriteEntry("INFO (EventLoggerApp.Execute): Thread aborted.");
  }
}

The code will keep on looping until a ThreadAbortException is caught. Inside the loop a message is written to the Windows Event Log and then the thread is put to sleep for 60 seconds (1 minute) using Thread.Sleep.

Start method

This method is responsible for starting the execution of the application logic. This method will initialize the Windows Event Log. If a separate Event Log source does not yet exist it will be created. The ‘Start’ method will also initialize and start the separate thread which will run the ‘Execute’ method. The code for this method is show below.

public void Start()
{
  // Check if the EventLoggerService Event Log Source exists, when not
  // create it
  if (!EventLog.SourceExists("EventLoggerSource"))
    EventLog.CreateEventSource("EventLoggerSource", "Event Logger");
  _log = new EventLog("EventLoggerSource");
  _log.Source = "EventLoggerSource";
 
  _thread = new Thread(new ThreadStart(Execute));
  _thread.Start();
}

Stop method

The ‘Stop’ method will make sure the thread running the ‘Execute’ method will be aborted so the application logic is stopped. The code is really easy and is shown below.

public void Stop()
{
  if (_thread != null)
  {
    _thread.Abort();
    _thread.Join();
  }
}

The ‘Stop’ method will first stop the thread using the ‘Abort’ method and then will wait for the thread to die before it will continue using the ‘Join’ method.

Implementing the ‘EventLoggerService’ class

The ‘EventLoggerService’ class has been automatically created by Visual Studio when we created the new Windows Service project. This class contains event handlers which will respond to the starting and stopping of the Windows Service. Here we need to implement some logic to communicate with the ‘EventLoggerApp’ class to make sure the application logic is started or stopped when the Windows Service is started or stopped. To do this right click on the ‘EventLoggerService.cs’ file and select the option “View Code”. The code should look like the following:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
 
namespace EventLogger
{
  public partial class EventLoggerService : ServiceBase
  {
    public EventLoggerService()
    {
      InitializeComponent();
    }
 
    protected override void OnStart(string[] args)
    {
      // TODO: Add code here to start your service.
    }
 
    protected override void OnStop()
    {
      // TODO: Add code here to perform any tear-down necessary to stop your service.
    }
  }
}

As you can see from the TODO comments in the code above, we need to implement the ‘OnStart’ and ‘OnStop’ event handlers. These event handlers are triggered when the Windows Service is being started, stopped or restarted using the Windows Service Manager (or using the “NET START” and “NET STOP” commands).

The implementation of the ‘OnStart’ and ‘OnStop’ event handlers is discussed in the following paragraphs. However before we start it is important to define a global variable of type ‘EventLoggerApp’ which will represent the application logic. To do so add the following code directly beneath the ‘EventLoggerService’ class decleration:

#region Member fields
// Private fields
private EventLoggerApp _app = new EventLoggerApp();
#endregion Member fields

The “OnStart” event handler

The “OnStart” event handler is triggered when the EventLogger Service is being started or when it is restarted (in this case the “OnStop” event handler is called first). So this method has to make sure that the application is started. Using the “EventLoggerApp” class we created earlier this is a piece of cake. Modify the ‘OnStart’ event handler so it will look as shown below.

protected override void OnStart(string[] args)
{
  if (_app == null)
    _app = new EventLoggerApp();
 
  _app.Start();
}

This code will make sure that an instance of the ‘EventLoggerApp’ class is created if one didn’t exist already. And next it will call the ‘Start’ method on the ‘EventLoggerApp’ class to start executing the application logic.

The “OnStop” event handler

The “OnStop” event handler is being triggered when the EventLogger Service is being stopped or restarted. So this event handler needs to make sure that the application is stopped and running tasks are aborted. Using our ‘EventLoggerApp’ this is again very easy. Modify the “OnStop” event handler so it will look as shown below.

protected override void OnStop()
{
  if (_app != null)
    _app.Stop();
}

The code will call the ‘Stop’ method of the ‘EventLoggerApp’ class if there is a valid instance of the ‘EventLoggerApp’. This will abort the execution of the application logic and will stop the application itself.

Implementing the “Program” class

The “Program” class is generated by the Windows Service template when creating a new Windows Service project. This class contains the entry point (the ‘static void Main(string[] args’ method) of the application.

In the “Main” method we will determine if the application has to be started as a ‘Console’ or a ‘Windows Service’ application. This will be done based on the supplied command line arguments. To realize this we need to modify the “Program” class as shown below.

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Text;
 
namespace EventLogger
{
  static class Program
  {
    [DllImport("kernel32.dll")]
    public static extern Boolean AllocConsole();
 
    ///
 
    /// The main entry point for the application.
    /// 
 
    static void Main(string[] args)
    {
      if (args.Length > 0 && args[0].ToLower() == "/console")
      {
        AllocConsole();
 
        EventLoggerApp app = new EventLoggerApp();
        app.Start();
 
        string input = string.Empty;
        Console.Write("Eventlogger Console started. Type 'exit' to stop the application: ");
 
        // Wait for the user to exit the application
        while (input.ToLower() != "exit") input = Console.ReadLine();
 
        // Stop the application.
        app.Stop();
      }
      else
      {
        // Initialize and run the service
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] { new EventLoggerService() };
        ServiceBase.Run(ServicesToRun);
      }
    }
  }
}

The lines 11 and 12 define the external method “AllocConsole” from the “kernel32.dll”. This definition makes sure we can attach a Console window to our application. This definition is necessary since we created the project based on the ‘Windows Service’ template and this template doesn’t contain this definition. At the moment we will call the “AllocConsole” method (see line 21) the operating system (Windows) will open a Console window and attach it to our process.

Another important modification is in the definition of the “Main” method. This method now accepts a array of strings called “args”. This array will contain the command line arguments which are supplied when starting the application. We will use this array to determine if the application should be started as a Console application or a Windows Service.

When the “Main” method is called we check if any command line parameters are supplied (line 19) and if so if it equals the string “/console”. When this is the case the application will be started as a Console application. This means the “AllocConsole” method is called and the ‘EventLoggerApp’ class is initialized and started. Next a loop is started where we wait for the user to type “exit” to stop the application. When the user enters the “exit” command, the loop is exited and the application is stopped by calling the “Stop” method on the “EventLoggerApp” class.

When no parameter is supplied from the command line or when it is not equal to “/console” the application is started as a Windows Service. The code to do so is exactly the same as the code that was generated by the Windows Service template.

Debugging the application

From this point we should be able to start the application as a Console application. We could do this by building the source, start a command line, browse to the bin folder and start the application by typing “EventLogger.exe /console”; however, it would be much easier to be able to hit the F5 button and start the application directly from Visual Studio. This can be done easily by making a few small changes to the project properties. First right-click in the Solution Explorer on the ‘EventLogger’ project name and select “Properties”. Now in the ‘EventLogger’ properties window click the tab “Debug”. Now enter the string “/console” in to the “Command line arguments:” field (see screenshot) and save your changes. When you now hit the F5 button, Visual Studio will start the application with the “/console” command line argument and the application will start in Console mode.

Modifying the “ProjectInstaller” class

The “ProjectInstaller” class handles the registration of the application as a Windows Service in Windows. This class is used by the “InstallUtil.exe” utility.

For our modifications we do not need to write any code, they can be done through the Visual Studio Designer. Open the “ProjectInstaller” in design view by double clicking the file “ProjectInstaller.cs” from the Solution Explorer. Next select (in the grey area) the component “serviceInstaller1″ and rename it to “eventLoggerServiceInstaller” using the “Properties” pane (see screenshot).

Next select the “serviceProcessInstaller1″ and rename it to “eventLoggerProcessInstaller”. Here you can also change the account which should be used to start the Windows Service (see screenshot). I usually set it to run as “LocalSystem”.

This will finish the modifications on the “ProjectInstaller” class and the application is now ready to be installed as a Windows Service using the “IntallUtil.exe” utility. In the next paragraphs I will explain how to implement the “Install.cmd” and “Uninstall.cmd” to make installing and uninstalling the service a lot easier.

Creating the “Install.cmd” and “Uninstall.cmd” batch scripts

To ease the process of installing and uninstalling the EventLogger application as a Windows Service we will create two batch scripts.

The scripts will execute the ‘InstallUtil.exe’ utility which will register the application using the “ProjectInstaller” class we modified in the previous paragraph.

NOTE: while debugging the application or running it as a Console application there is no need to install it first. Installing is only necessary when you want to run the application as a Windows Service.

The “Install.cmd” and “Uninstall.cmd” scripts are almost identical. The only difference is that in the “Install.cmd” script the “InstallUtil.exe” utility is executed using the “/i” command line parameter, while the “Uninstall.cmd” script executes the “InstallUtil.exe” utility with the “/u” command line parameter. Both scripts are listed below.

Install.cmd:

@ECHO OFF
 
REM The following directory is for .NET 2.0
set DOTNETFX2=%SystemRoot%\Microsoft.NET\Framework\v2.0.50727
set PATH=%PATH%;%DOTNETFX2%
 
echo Installing EventLogger Service...
echo ---------------------------------------------------
InstallUtil /i EventLogger.exe
echo ---------------------------------------------------
echo Done.

Uninstall.cmd:

@ECHO OFF
 
REM The following directory is for .NET 2.0
set DOTNETFX2=%SystemRoot%\Microsoft.NET\Framework\v2.0.50727
set PATH=%PATH%;%DOTNETFX2%
 
echo Uninstalling EventLogger Service...
echo ---------------------------------------------------
InstallUtil /u EventLogger.exe
echo ---------------------------------------------------
echo Done.

Another useful thing to configure is to copy the “Install.cmd” and “Uninstall.cmd” batch scripts to the “bin\debug” or “bin\release” directories upon compilation. This can be done in the following way. Right-click on the “EventLogger” project name in the Solution Explorer and select “Properties”. Click the tab “Build Events” in the “EventLogger” window which opened. And add the following line in the “Post-build event command line:” field (see screenshot):

copy "$(ProjectDir)*.cmd" "$(TargetDir)*.cmd"

Now the batch scripts are automatically copied over to the bin directory together with the other project binaries. Installing the application as a Windows Service can now be done by double clicking the “Install.cmd” batch script from the bin folder. To uninstall it you can of course double click the “Uninstall.cmd” batch script.

This concludes the very very long article on building a Windows Service which also can be started as a Console application. Hopefully you found this post helpful, if you have any suggestions, questions or comments be sure to leave a message.

77 thoughts on “Tutorial – Building a Windows Service application in C#

  1. Very useful article. We have a Windows Service at my place of work that was a constant pain point. Your write up helped me improve its functionality. Thank you!

  2. There is one comment I would like to make when trying to run the application from command line. There is an error message poping up when starting it from command line without the -x parameter. “Cannot start service fro mthe command line or a debugger. …”
    So, maybe it should have a parameter -s (for service) and have no parameter as the standard command line application.

  3. Hi André,

    To run the application from the command line you will have to supply the “/console” parameter. So from the command line you should type something like “EventLogger.exe /console”. This is also explained in the article in the chapters “Implementing the Program class” and “Debugging the application”.

    When no parameter is supplied or the parameter doesn’t match the “/console” the application will try to start as a Windows Service (which is not allowed directly from the command line).

    Hope this helps,

    Regards Mauri

  4. Hi, the tutorial for windows service is great.however im unable to make out how to create a Windows Forms app with a service running in background. i have made the Form/App part but in a fix as to how to add a service in the same project.

  5. I do like this article as it did help me a bit on the way… but i did run in to some problem with SecurityException for adding to the log so i did have to add a manifest thing about admin.. is there a nicer way to get the log to get added without admin rights..

  6. Working with VS 2005 and most Windows Service articles are too recent. The ones I found didn’t have Event Logging, didn’t have command line arguments for running as a console. Thanks for doing a knowledgeable and thorough job.

  7. Pingback: Will my background thread continue the execution after I log out? | ASP Questions & Answers

Leave a Reply