Create a service for Windows in .NET 8
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 <サービス名>