Create a service for Windows in .NET 8

Page update date :
Page creation date :

Operating environment

Visual Studio
  • Visual Studio 2022
.NET
  • .NET 8
Windows
  • Windows 11

Prerequisites

Visual Studio
  • Visual Studio 2022
.NET
  • .NET 8
Windows
  • Windows 10
  • Windows 11
Windows Server
  • Windows 2012 or later

precondition

  • Visual Studio is already installed

At first

When I try to create a Windows service in Visual Studio .NET, there are only .NET Framework templates. It can also be created in .NET (Core), and the template is named "Worker Service".

In this article, I will explain how to use this to create, register, and run a Windows service. The processing content is minimal, so if you can confirm that it is running as a Windows service, please create the function.

Create a project

Start Visual Studio. Select Create a new project.

Enter in the サービス search field above, and then select Worker Service from the list. "Windows Services" is the .NET Framework version, which does not have a .NET version.

The project name and location can be arbitrary. It does not affect the service you are registering for.

「. NET 8.0 is selected, and leave the defaults to create it.

The project has been created.

Adding Libraries

In the initial state, it has only a "service" function and no Windows-specific functions. Add a library that can be used by a Windows service from NuGet.

Right-click Dependencies and select Manage NuGet Packages.

Select the Browse tab and enter in the Microsoft.Extensions.Hosting.WindowsServices search field. It will appear in the list, so install it.

Click Apply.

It was added as a package.

Editing Programs

This time, I will create a service that periodically adds text to a text file as a Mr./Ms..

Program.cs

Add the functionality of the Windows service as follows:

var builder = Host.CreateApplicationBuilder(args);
// ↓ここから追加
builder.Services.AddWindowsService();
// ↑ここまで追加
builder.Services.AddHostedService<Worker>();

var host = builder.Build();
host.Run();

Worker.cs

You can change the class name arbitrarily, but for this time we will leave the default.

By default, there are only methods that are ExecuteAsync processed when the service is executed, but let's change it as follows:

public class Worker : BackgroundService
{
  private readonly ILogger<Worker> _logger;

  /// <summary>ログの出力先フォルダパス。</summary>
  private const string OutputLogFolderPath = @"C:\Temporary\";

  /// <summary>ログの出力先ファイルパス。</summary>
  private const string OutputLogFilePath = @$"{OutputLogFolderPath}Test.log";


  public Worker(ILogger<Worker> logger)
  {
    _logger = logger;
  }

  /// <summary>
  /// サービスが開始されたときに呼ばれます。
  /// </summary>
  /// <param name="stoppingToken"></param>
  /// <returns></returns>
  public override async Task StartAsync(CancellationToken stoppingToken)
  {
    if (Directory.Exists(OutputLogFolderPath) == false)
    {
      Directory.CreateDirectory(OutputLogFolderPath);
    }
    File.AppendAllText(OutputLogFilePath, $"StartAsync サービスを開始しました。\r\n");

    await base.StartAsync(stoppingToken);
  }

  /// <summary>
  /// サービスが終了したときに呼ばれます。
  /// </summary>
  /// <param name="stoppingToken"></param>
  /// <returns></returns>
  public override async Task StopAsync(CancellationToken stoppingToken)
  {
    File.AppendAllText(OutputLogFilePath, $"StopAsync サービスを終了しました。\r\n");
    File.AppendAllText(OutputLogFilePath, $"------------------------------\r\n");

    await base.StopAsync(stoppingToken);
  }

  /// <summary>
  /// サービスが実行されたときに呼ばれます。
  /// </summary>
  /// <param name="stoppingToken">サービスの非同期キャンセルトークン。</param>
  /// <returns></returns>
  protected override async Task ExecuteAsync(CancellationToken stoppingToken)
  {
    while (!stoppingToken.IsCancellationRequested)
    {
      File.AppendAllText(OutputLogFilePath, $"{DateTime.Now}\r\n");

      if (_logger.IsEnabled(LogLevel.Information))
      {
        _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
      }
      await Task.Delay(1000 * 60, stoppingToken);
    }
  }
}

We've added a new method and StopAsync a new StartAsync method. As the name implies, these methods are called when the service is started and when it is stopped. The content of the process is simply creating folders and writing text, so I will omit the explanation.

ExecuteAsync The method continues to loop with stoppingToken until while it is flagged for cancellation. Add what while you want to be processed while the service is running. However, if you write only the process you want to move, the service will be running at full capacity, so Task.Delay it is basic to move it while waiting for a certain time with the method. By default, it is set to 1 second (1000ms), so please rewrite it at any time.

debug

You can debug from Visual Studio. Rest assured that you will not actually be registered with the service.

When you run it, the console will appear.

If the process is correct, you can see that the file has been created.

If you want to stop debugging, close the console.

If you check the log, you can see that the service start process has passed, but the termination process has not. To see the termination, you need to actually register with the Windows service to verify it.

issue

In order to be able to register with a Windows service, you must publish the program. Right-click the project and choose Publish.

Select Folders.

The folder location is nice by default.

The publishing settings will be created, so select "Show All Settings".

Set it up as follows:

Parameter Name Value Remarks
configuration Release (default)
Target Framework net8.0 (default)
Deployment Modes Framework Dependency Separately for the service registration environment. If you are installing the NEt 8 runtime, this setting is OK.
Target Runtime win-x64 If the OS is a 32-bit environment, select win-x86
Target Location default
Creating a single file ON
ReadyToRun Compilation arbitrary

After setting, click the "Submit" button.

If "Publishing was successful" is displayed in the lower left corner, it is complete.

The output file can be opened by clicking "Target Location".

Program Placement and Enrollment in Services

Log in to the environment where you want to register the Windows service with administrator privileges.

Copy the published file to the environment where you want to register it as a Windows service. You can place it in any folder, but keep in mind that the Windows service will always refer to the program in that folder.

Also, if the published file contains a file with the extension .pdb , do not copy it in an environment where it can be seen by an unspecified person because it contains development information.

Once the file is in place, register it as a Windows service. Use the command to register. Right-click on the Start menu and select "Terminal (Admin)". Mr./Ms. is running in a Windows 11 environment, but in other environments, it is OK to open a command prompt with administrator privileges.

In the case of the terminal, PowerShell may be open first, but PowerShell may not be able to set it up correctly, so open the "Command Prompt".

You can register it with the Windows service with the following command:

format

sc create "<サービス名>" start=auto binpath="<プログラム(.exe)のパス>"

Example Input

sc create "WindowsServiceDotNet8" start=auto binpath="C:\Service\WindowsServiceDotNet8\WindowsServiceDotNet8.exe"

<サービス名> is the name that appears in the list of Windows services. You can set a separate display name, but if you do not specify a display name, this name will be displayed. It also affects the registry, so alphanumeric service names are preferred.

start=auto is a setting to automatically start the service when Windows starts. If you want to start it manually, delete this description.

binpath is the full path of the program files.

If you execute the command and [SC] CreateService SUCCESS display , it is successful.

The services you registered should appear in the list.

Start the service and check its operation

If you want to run the service, you can start it from the service screen or with the following command.

sc start <サービス名>

The stop command is as follows.

sc stop <サービス名>

If you stop the service, you can verify that the shutdown process is running.

Add a description to the service

The description field of the added service is blank, but you can add it with the following command.

sc description <サービス名> "<説明文>"

Deleting a Service

If you want to delete the service, you can do so with the following command. You must have administrator privileges at the command prompt.

sc delete <サービス名>