受欢迎的博客标签

ASP.NET Core Background Service(3)-How to write and Install .NET Core Worker Service as Windows Services

Published

Introduction


In this tutorial you’ll set up and deploy a production-ready ASP.NET Core application   on Windows or Ubuntu 18.04 using  worker  service .

 

os:windows server 2012 R2

.net core:net core 3.1.1

or

.net 5.x

or

.Net 8.x

1. Create a worker  service application

step 1:Creating  a Default .NET Core worker service application

Create a Worker on the command line:

dotnet new worker -o Stockso.WindowsService
public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }
 
    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices(services =>
            {
                services.AddHostedService<Worker>();
            });
}

 

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;
 
    public Worker(ILogger<Worker> logger)
    {
        _logger = logger;
    }
 
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation($"Worker running at: {DateTime.Now}");
            await Task.Delay(1000, stoppingToken);
        }
    }
}

step 2: Extending worker service

Worker service class inherits from BackgroundService defined in Microsoft.Extensions.Hosting.Abstractions package,We can  override: StartAsync(), StopAsync() and Dispose(). StartAsync() and StopAsync() are inherited from IHostedService interface.

public abstract class BackgroundService : IHostedService, IDisposable
{
    public virtual void Dispose();
    public virtual Task StartAsync(CancellationToken cancellationToken);
    public virtual Task StopAsync(CancellationToken cancellationToken);
    protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
}

 

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace Stockso.WindowsService
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;

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

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
        }

        public override Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation($"{DateTime.Now}: Worker started.");

            return base.StartAsync(cancellationToken);
        }


        public override Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation($"{DateTime.Now}:Worker stopped. ");

            return base.StopAsync(cancellationToken);
        }

        public override void Dispose()
        {
            _logger.LogInformation($"{DateTime.Now}:Worker disposed.");

            base.Dispose();
        }
    }
}

step 3:Test the Application Directly at a command prompt

Run the app at a command prompt

output:

cd G:\xx\WorkerService
dotnet run
info: Stockso.WindowsService.Worker[0]
      2020/6/20 3:58:26: OutIpService.WorkerService Worker started.
info: OutIpService.WorkerService.Worker[0]
      Worker running at: 06/20/2020 03:58:26 +08:00
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: G:\xxx\src\OutIpService\OutIpService.WorkerService

info: Microsoft.Hosting.Lifetime[0]
      Application is shutting down...
info: OutIpService.WorkerService.Worker[0]
      2020/6/20 3:58:30:OutIpService.WorkerService Worker stopped. 
info: OutIpService.WorkerService.Worker[0]
      2020/6/20 3:58:30:OutIpService.WorkerService Worker disposed.

 

 

step 4:publish 

dotnet publish -o C:\path\to\project\pubfolder

or

cd F:\stock\ReadDZHRealTime\src\WinTimerTask\Stockso.WorkerService\
dotnet publish -c release

you can get

 

G:\stock\ReadDZHRealTime\src\WinTimerTask\Stockso.WindowsService\bin\release\net5.0\publish\Stockso.WindowsService.dll
and
G:\stock\ReadDZHRealTime\src\WinTimerTask\Stockso.WindowsService\bin\release\net5.0\publish\Stockso.WindowsService.exe

2.Run  .NET Core Worker Service as a Windows Service

Install the Worker service on windows 2012 R2(Run as a Windows Service)

Install the Worker as Windows Services

step 1.preprare Windows service

In order to run as a Windows Service we need our worker to listen for start and stop signals from ServiceBase the .NET type that exposes the Windows Service systems to .NET applications.

To do this we want to:

Add the Microsoft.Extensions.Hosting.WindowsServices NuGet package

 

<Project Sdk="Microsoft.NET.Sdk.Worker">

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
   
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />
    <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="5.0.1" />
  </ItemGroup>
</Project>

Add the UseWindowsService call to the HostBuilder in our Program.cs

public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
              .UseWindowsService()
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker>();
                });

 

first,publish the Worker Service as an exe file with dependencies.

run the following dotnet command:

dotnet publish -o C:\path\to\project\pubfolder

step 2.create Windows Services 

second,Run the sc utility (from Windows\System32) to create a new service.

you must run cmd as administrators Windows PowerShell then you can create Windows Services .Then we can use the sc utility in an admin command prompt:

C:\Windows\System32\sc create Stockso.WindowsService binPath=F:\stock\ReadDZHRealTime\src\WinTimerTask\Stockso.WindowsService\bin\release\net5.0\publish\Stockso.WindowsService.exe

output

PS C:\Windows\system32> C:\Windows\System32\sc create Stockso.WindowsService binPath=F:\stock\ReadDZHRealTime\src\WinTimerTask\Stockso.WindowsService\bin\release\net5.0\publish\Stockso.WindowsService.exe
[SC] CreateService 成功

otherwise,you can get error:

[SC] OpenSCManager 失败 5:拒绝访问

step 3.Start Windows Services 

Three, start  Stockso.WindowsService

sc start Stockso.WindowsService

other:Create and manage the Windows Service

sc.exe create Stockso.WindowsService DisplayName= "Stockso.WindowsService" binpath= "C:\Program Files\dotnet\dotnet.exe G:\stock\ReadDZHRealTime\src\WinTimerTask\Stockso.WindowsService\bin\release\netcoreapp3.1\publish\Stockso.WindowsService.dll --run-as-service"


sc start Stockso.WindowsService
sc stop Stockso.WindowsService
sc delete Stockso.WindowsService
sc config Stockso.WindowsService start=AUTO    
sc config Stockso.WindowsService start= DEMAND  
sc config Stockso.WindowsService  start= DISABLED

net start Stockso.WindowsService
net stop Stockso.WindowsService

System and Application Event Logs

Default the EventLogLoggerProvider to warning or above.you must use:

 _logger.LogWarning($"some information");          
  

 

error

   public override Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation($"{DateTime.Now}: {applicationName} Worker started.");        
             
            return base.StartAsync(cancellationToken);
        }

correct

 public override Task StartAsync(CancellationToken cancellationToken)
        {             
            _logger.LogWarning($"{DateTime.Now}: {applicationName} Worker started.");          
            return base.StartAsync(cancellationToken);
        }

 

Access the System and Application Event Logs:

Open the Start menu, search for Event Viewer, and select the Event Viewer app.
In Event Viewer, open the Windows Logs node.
Select System to open the System Event Log. Select Application to open the Application Event Log.
Search for errors associated with the failing app.

 

3.Install the Worker service on Linux

preprare Linux service

Add the Microsoft.Extensions.Hosting.Systemd NuGet package

Add the UseSystemd() call to the HostBuilder in our Program.cs

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .UseSystemd()
        .ConfigureServices((hostContext, services) =>
        {
            services.AddHostedService<Worker>();
        });

 

resource

1.Host ASP.NET Core 3.x in a Windows Service

https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/windows-service?view=aspnetcore-3.1&tabs=visual-studio

Host ASP.NET Core 8.x in a Windows Service

https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/windows-service?view=aspnetcore-8.0&tabs=visual-studio

2.Worker Service sample

https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/host-and-deploy/windows-service/samples/3.x

https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/host-and-deploy/windows-service/samples/7.x/WebAppServiceSample

3.CreateDefaultBuilder(string[] args)

4.worker-scope/Worker.cs

https://github.com/dotnet/docs/blob/5b3c2b35bf6d9298cdb5129466b868f6f6e99fd7/docs/core/extensions/snippets/configuration/worker-scope/Worker.cs

 

5.Turn Your .NET Worker Service into an Awesome Linux Systemd Service

https://www.aloneguid.uk/posts/2023/05/csharp-dotnet-linux-daemon/