Create a Windows Service installer

When you create a .NET Windows Service (not to be mistaken with a .NET Framework Windows Service), you may want to create an installer for your service. Without an installer, users would have to know how to install and configure your service. An installer bundles your app's executables and exposes a customizable installation user experience.

In this tutorial, you'll learn how to:

  • Install the Visual Studio Installer Projects extension.
  • Create a setup project.
  • Update an existing .NET Worker project to support installation.
  • Automate the installation and uninstallation with the Windows Service Control Manager.

Prerequisites

Install the extension

Install the Microsoft Visual Studio Installer Projects extension. After installing, restart Visual Studio and you'll see new project templates available.

Update existing project

This tutorial is based on the app created as part of the Create a Windows Service using BackgroundService tutorial. You can either clone the sample repo or use the app you built in the previous tutorial.

Tip

All of the "Workers in .NET" example source code is available in the Samples Browser for download. For more information, see Browse code samples: Workers in .NET.

Open the solution in Visual Studio, and select F5 to ensure that the app builds and runs as expected. Press Ctrl+C to stop the app.

Handle installation switches

The Windows Service app needs to handle installation switches. The setup project will call into the Windows Service app with /Install and /Uninstall switches during installation and uninstallation respectively. When these switches are present, the app will behave differently, in that it will only perform installation or uninstallation using the Windows Service Control Manager executable (sc.exe).

For the app to call a separate process, install the CliWrap NuGet package as a convenience. To install the CliWrap package, use the dotnet add package command:

dotnet add App.WindowsService.csproj package CliWrap

For more information, see dotnet add package.

With CliWrap installed, open the Program.cs file of the App.WindowsService project. After the using statements, but before the IHost is created, add the following code:

using CliWrap;

const string ServiceName = ".NET Joke Service";

if (args is { Length: 1 })
{
    string executablePath =
        Path.Combine(AppContext.BaseDirectory, "App.WindowsService.exe");

    if (args[0] is "/Install")
    {
        await Cli.Wrap("sc")
            .WithArguments(new[] { "create", ServiceName, $"binPath={executablePath}", "start=auto" })
            .ExecuteAsync();
    }
    else if (args[0] is "/Uninstall")
    {
        await Cli.Wrap("sc")
            .WithArguments(new[] { "stop", ServiceName })
            .ExecuteAsync();

        await Cli.Wrap("sc")
            .WithArguments(new[] { "delete", ServiceName })
            .ExecuteAsync();
    }

    return;
}

The preceding code:

  • Declares the service name as a const string value.
  • Checks the args for a single value.
  • Gets the executable path from the AppContext.BaseDirectory.
  • When the "/Install" switch is present, sc create ".NET Joke Service" binPath="path/to/App.WindowsService.exe" start=auto is called.
  • When the "/Uninstall" switch is present, sc stop ".NET Joke Service" and sc delete ".NET Joke Service" are called.

When no installation switches are present, the app behaves as it did before, but it now includes installation functionality.

Add new setup project

To add a new setup project, right-click on the solution in the Solution Explorer and select Add > New Project:

Add new project dialog: New Setup Project.

Select Setup Project from the available templates, then select Next. Provide the desired Name and Location, then select Create.

Configure installer project

To configure the install project, select the project in the Solution Explorer. Select F4 to open the project properties pane. You can configure the app's "add" and "remove" icons, author, manufacturer, product name, title, target platform, and so on.

Installer project properties pane.

The installer project needs to define two custom actions for installation behavior. Right-click the project in the Solution Explorer, and then select View > Custom Actions.

Installer project Custom Actions context menu.

From the Custom Actions window, select Install > Add Custom Action.

Custom Actions properties dialog: select item.

Double-click the Application Folder, and select Publish Items from App.WindowsService (Active).

Custom Actions properties dialog: select item app folder.

Select Ok to confirm the selection. Right-click the added Publish Items from App.WindowsService (Active) node under Install, then select Properties.

Publish items properties.

Add /Install to the Arguments. Follow these same steps for Uninstall, adding /Uninstall to the Arguments.

Once you've done both, you should see the following:

Custom Actions with Install and Uninstall actions defined.

With these updates, the setup project has been configured to delegate its Install and Uninstall actions to call into the Windows Service app with appropriate arguments.

Test installation

To test the installer, expand Solution Configurations in Visual Studio, and select Release (assuming Debug was selected). Build the solution and then right-click on the setup project and select Build. By default, setup projects are not part of the build.

Select View > Output, and ensure that the Show output from dropdown has Build selected. The Microsoft Installer (MSI) file path is displayed. Copy the path, and open the installer. Run the installer:

1. Installer welcome dialog Installer welcome dialog.

2. Installer select folder dialog Installer select folder dialog.

3. Installer confirm dialog Installer confirm dialog.

4. Installer complete dialog Installer complete dialog.

Once the service is installed, you can open Services to start the service. To uninstall the service, use the Windows Add or Remove Programs feature to call the installer.

See also