C#: create a basic windows service

The service

Creating services in C# differs a bit from creating a standard console/winform/wpf application. A service is often created to run continuously and it has no graphical interface, something which makes it hard to communicate errors to the user.
This post will show you how to create a very basic windows service which communicates with the user through the event handler!

First up, create a console project and call it something nice, such as TestService:

Add a console project
Add a console project

 

Add references to the project to System.ServiceProcess and System.Configuration.Install. Then add a new item,a windows service, called TestService.cs and let it inherit from ServiceBase:

Windows Service now, Installer for later
Windows Service now, Installer for later
namespace TestService
{
    partial class TestService: ServiceBase
    {
        public TestService()
        {
            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.
        }
    }
}

TestService comes with a few methods you can override. You should at least override OnStart and OnStop as these let you control what happens when the service starts and stops:

namespace MyFirstService
{
    public class MyService : ServiceBase
    {
        public MyService()
        {
            InitializeComponent();
            this.ServiceName = "MyService";
        }
 
        protected override void OnStart(string[] args)
        {
            base.OnStart(args);
        }
 
        protected override void OnStop()
        {
            base.OnStop();
        }
    }
}

Call the base implementation first and then add whatever you want to do afterwards. To make sure this service in the one that’s run we go to the program.cs class and call for this service on execution:

namespace TestService
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceBase.Run(new ServiceBase[]
            {
                new TestService()
            });
        }
    }
}

The installer

Now, this won’t install as normal and the easiest way to install it is to create an installer class and then add a setup project to handle it. We start by adding a new item, an installer item (see image above), called TestServiceInstaller.cs which we let inherit from the Installer class in System.Configuration.Install. Add the code as shown below:

namespace TestServiceService
{
    [RunInstaller(true)]
    public class TestServiceInstaller : Installer
    {
        public MyServiceInstaller()
        {
            ServiceProcessInstaller serviceProcessInstaller =
                               new ServiceProcessInstaller();
            ServiceInstaller serviceInstaller = new ServiceInstaller();
 
            //Who will run this service?
            serviceProcessInstaller.Account = ServiceAccount.LocalSystem;
            //Set login credentials if needed
            //serviceProcessInstaller.Username = ?;
            //serviceProcessInstaller.Password = ?;
 
            //This is the name that is displayed in the service menu
            serviceInstaller.DisplayName = "My test service";
 
            //How will the service act on startup?
            serviceInstaller.StartType = ServiceStartMode.Manual;
 
            //The actual name of the service, must be the same
            //as in your ServiceBase
            serviceInstaller.ServiceName = "TestService";
 
            this.Installers.Add(serviceProcessInstaller);
            this.Installers.Add(serviceInstaller);
 
            this.Installers.Add(serviceProcessInstaller);
            this.Installers.Add(serviceInstaller);
 
            InitializeComponent();
        }
    }
}

This is just a basic installer class and you need to configure at least the ServiceName and the DisplayName to match your preferences. The ServiceName must match your services name or else it won’t install.

Communicate using the EventLog

The easiest way to communicate with the user is to use the EventLog. If you haven’t seen or used it before you can open it by going to Start => Control Panel => Administrative Tools => EventLog (or Event Viewer in Vista). The EventView is where services and programs can output information to a user and it is very handy.
To configure an EventLog go back to the TestService.cs and change it to this:

namespace TestService
{
    public class TestService: ServiceBase
    {
        private const string Source = "TestServiceLog";
        private const string Log = "Application";
 
        private EventLog m_EventLog;
 
        public TestService()
        {
            this.ServiceName = "TestService";
 
            ConfigureEventLog();
        }
 
        protected override void OnStart(string[] args)
        {
            base.OnStart(args);
 
            m_EventLog.WriteEntry("TestServiceis starting!");
        }
 
        protected override void OnStop()
        {
            base.OnStop();
 
            m_EventLog.WriteEntry("TestServiceis stopping!");
        }
 
        private void ConfigureEventLog()
        {
            if (!EventLog.SourceExists(Source))
            {
                EventLog.CreateEventSource(Source, Log);
            }
 
            m_EventLog.Source = Source;
            m_EventLog.Log = Log;
 
            m_EventLog.WriteEntry("EventLog configured!");
        }
    }
}

The EventLog must be configured before using and it is prudent to check if the source exists. You don’t know if it exists on another computer and the EventLog will crash if it doesn’t.

A Setup-project

Now to the installation and usage of our fine service. Add a Setup project and call it ServiceSetup:

Add setup project
Add setup project

Add the service project by right clicking on the setup project and selecting View => File System and enter the Application Folder. Right click in the application folder and select Add => Project Output :

Configuring the setup project
Configuring the setup project

Select the project as follows:

Adding the project output
Adding the project output

Now, there is one more thing to do in order to get this to work. If you just install normally now the files will be copied to the installation directory complete but the service won’t get registered and it will have been quite pointless. We need to right-click on the project once more and select View => Custom Actions and add our project output there:

Custom actions
Custom actions

Now, if you right-click on the setup project and build it (setup projects generally has to be build individually as they are not included in the building schedule, change it by right-clicking by going to Solution configurations => Configuration manager). After building the project, right-click on it and select install.

Using the installed service

Go to Start => Control Panel => Administrative Tools => Services and find your service (by its display name):

One thought on “C#: create a basic windows service

Leave a Reply