Creating a Windows Service Application

Summary

In this post, I’m going to show you the easiest way to get a service application up and running. Windows Services can be used to perform background tasks while your computer or server continues to perform normal tasks. Services can also run while a computer is logged out.

Getting Started

The first thing I do when I design a service application is separate the service part from the core code. I also provide a method of testing my code while not in a service, so I can get feedback on a console screen and put breakpoints in the code instead of trying to read log files and reverse-engineer what is wrong with my program.

So step 1 is to setup a solution with three projects in it. The first project is the core project itself. This will be a C# library project and will all of the code that my program will use for it’s functions. The second project will be a console application. This application will do nothing more than call the entry program of the core project. This console application will be used to troubleshoot issues. The last project will be the service application. This project will contain the service code plus an installer. The service application does no more than the console application, call the entry program of the core project. (see project selector below):

Don’t forget to set your console application as the default startup application (Right-click, select “Set as StartUp Project”).

Setting up the Installer

Technically, you don’t need an installer for your service, you can just manually install your program from powershell. However, it is much easier to create an installer and then create a powershell script to check if the service is installed, and run your installer if it is not. To add an installer, open your service project and double-click on the file named “Service1.cs” (assuming you left it the default file name). You’ll be on a blank designer window. Right-click on the designer window background and you’ll see this menu:

You should see something like this:

Select “Add Installer” and another file will appear in your project. The default name is “ProjectInstaller.cs”. Now expand the file by clicking on the triangle next to the “ProjectInstaller.cs” file and double-click on the file named “ProjectInstaller.Designer.cs”. Open the region named “Component Designer Generated Code” where we can add a few lines of code. The following snap shot highlights the added lines of code:

Connecting the Console and Service Applications to Core

Inside your console application, right-click on “References” and add the solution core. Inside your services application, do the same, right-click on “References” and add the solution core. Now you have to add the proper “using” statement at the top of your console application “Program.cs” file and add the “using” statement to your service application (called the “Service1.cs” file, right-click on Service1.cs and select “View Code”) so your console and service applications can reference the core project.

Writing Your Core Application

Now we need to create a starting program cs file, I’ll call it “StartingClass.cs” which is the beginning of the program. Here’s the program shell:

public class StartingClass
{
    private volatile bool _stopAgent;
    private static StartingClass _instance;

    public static StartingClass Instance
    {
        get { return _instance ?? (_instance = new StartingClass()); }
    }

    private StartingClass()
    {
        _stopAgent = false;
    }

    public bool Stopped { get; private set; }

    public void Start()
    {
        ThreadPool.QueueUserWorkItem(action =>
        {
            while (!_stopAgent)
            {
                // do something here
                using (StreamWriter writer = new StreamWriter("c:\TestService.txt", true))
                {
                  writer.WriteLine("Service is running " + DateTime.Now.ToString("H:mm:ss"));
                }

                if (!_stopAgent)
                {
                    Thread.Sleep(5 * 1000); // wait 5 seconds
                }
            }

            Stopped = true;

        }, TaskCreationOptions.LongRunning);
    }

    public void Stop()
    {
        _stopAgent = true;
    }
}

You’ll have to add “usings” for these three dlls:

using System.Threading.Tasks;
using System.Threading;
using System.IO;

The first thing that this object does is provide a static instance. This is just for convenience. The constructor initializes the _stopAgent value to false. This will be set by the calling program (either the console when the user hits a key or the service when someone clicks the service stop button). The “Start()” method is the guts of this program. This is wrapped in a threadpool so that your service doesn’t get hung when you start it up. The service will kick off your program and then continue on it’s way (which we will program to remain idle). Inside the threadpool is your program’s main loop. You can process something inside this loop (calling other classes if necessary) until the service is stopped. For this little sample, I’m just going to keep appending the current time to a text file on the C: drive every 5 seconds.

Your Console Application

Let’s get the console application together so we can test the code before moving on to the actual service application. The code for your console application should pretty much always look like this:

static void Main(string[] args)
{
    StartingClass.Instance.Start();

    Console.WriteLine("Press any key to gracefully stop the processing...");
    Console.ReadKey();
    StartingClass.Instance.Stop();

    Console.WriteLine("Processing stopped. Press any key to exit...");
    Console.ReadKey();
}

Now run your console application and see what happens. First, you’ll see the console screen appear and wait for input to stop. If you navigate to your C: drive and find the “TestService.txt” file, you can open it and see the time inside. If you close it and re-open it after 5 seconds have elapsed, you’ll another time appended to the file. This will continue until you stop your console application.

Your Service Application

Now go to your service application. Find “Service1.cs”, right-click on it and “View Code”. You will see an OnStart() and an OnStop() method inside the main class. You will call your start() method from the OnStart() and call your stop method inside your OnStop() method. Yes, it’s that easy.

The Powershell Installation Script

Here’s the script to install or re-install your service (name it powershellscript.ps1):

#If service is installed, stop it; else install it.
$serviceFullPath = "path_to_service_exe_fileBlogServiceSample.exe"

Write-Host "Installing service..." -foregroundcolor cyan

Invoke-Command -ScriptBlock { C:WINDOWSMicrosoft.NETFrameworkv4.0.30319InstallUtil.exe /install "$serviceFullPath"}
}

Write-Host "Starting MyService service..." -foregroundcolor cyan
Start-Service MyService

Write-Host "Deployment Complete!" -foregroundcolor Green

You’ll have to navigate to the path of our service executable and paste it into the script above (you can download the file and change the path name). Then you’ll have to start up powershell. Run powershell as an administrator:

If you’ve never run powershell before, you’ll probably have to run a command to make it override the system script safety. Otherwise you’ll get a message indicating that your script cannot be loaded because the execution of scripts is disabled on this system…etc. etc.

So Run the following command:

set-executionpolicy remotesigned

Then run your script:

./powershellscript.ps1

and you should see something like this:

Obviously, the path to your source will be different from mine, but the end of your script should produce the same “Deployment Complete!” message.

Verify Your Service is Running

Go to your control panel -> System and Security -> Administrative Tools and double-click on “Services”. You should be able to scroll down and find a service called “MyServiceDisplay”. Now you know where that is set in your program (inside the ProjectInstaller.cs file). If you double-click on that line, you’ll see that your service is already started and the service name is “MyService”. Now go to your C: drive and you should see a text file named “TestService.txt”. Open this file and you’ll see new time entries. Close and open this file and additional time entries should appear at 5 second intervals. Cool eh?

Stopping Your Service

Go back to the Services control panel and double-click on “MyServiceDisplay” and you’ll see the properties window:

Click the “Stop” button and your service should stop. Check your text file and make sure no more times are appearing. You have verified that your service works.

If you change your program, you will need to manually stop your service, re-build your application, then manually restart your service. If you are creating a deployment script you’ll want to make your script stop the service (if it is already installed) copy the exe file over the existing one and then restart the service. If you want to be safe and provide a roll-back capability, you’ll need to stop your service, copy your new exe into a new directory every time, then change the path of the service to point to the new service and start it back up. I’ll leave that for another blog post.

Deleting a Service

Open a command window (Start menu, type in “CMD”), then type in:

sc delete MyService

You should see a confirmation message:

[SC] DeleteService SUCCESS

Source Code:

BlogServiceSample.zip
powershellscript.zip

Leave a Reply