受欢迎的博客标签

ASP.NET Core Background Service(3)-.NET Core Worker Service Send dynamic IP address to mailbox -OutIpService.

Published

os:windows server 2012 R2

.net core:net core 3.1.1  .net 8.x

net core 3.1.1

1. Create a worker

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

Create a Worker on the command line:

dotnet new worker -o OutIpService.WorkerService
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);

               //get/send ip address 
                await CheckOutIp(stoppingToken);  

                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();
        }
    }
}

Test the Application Directly at a command prompt

output:

info: OutIpService.WorkerService.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: OutIpService.WorkerService.Worker[0]
      06/20/2020 03:58:27 +08:00 Current IP is: 128.47.44.121
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 3:publish 

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

or

cd G:\stock\ReadDZHRealTime\src\WinTimerTask\Stockso.WindowsService
dotnet publish -c release

you can get

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

OutIpService.WorkerService -> F:\stock\ReadDZHRealTime\src\OutIpService\OutIpService.WorkerService\bin\release\net8.0
  \OutIpService.WorkerService.dll
and
  OutIpService.WorkerService -> F:\stock\ReadDZHRealTime\src\OutIpService\OutIpService.WorkerService\bin\release\net8.0
  \publish\OutIpService.WorkerService.exe

step 4: Add System and Application Event Logs

Default the EventLogLoggerProvider to warning or above.Event Logs are filtered at the warning level by default now. Thus, you cannot see any System and Application Event  information level logs on system Event Viewer.

https://github.com/dotnet/extensions/src/Hosting/Hosting/src/Host.cs source 

//Gets the current working directory of the application.
            _logger.LogWarning($"the current working directory of the application;{Environment.CurrentDirectory}");

 

 

using Microsoft.Extensions.Logging;


namespace OutIpService.WorkerService
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
              .ConfigureLogging(logging =>
              {
                  logging.AddEventLog();
                  logging.AddEventSourceLogger();
                  logging.SetMinimumLevel(LogLevel.Debug);
              })
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker>();
                });
    }
}

Test the System and Application Event Logs 

Let's test Test the System and Application Event Logs  with warning level :

  //Gets the current working directory of the application.
            _logger.LogWarning($"the current working directory of the application;{Environment.CurrentDirectory}");

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.

日志名称:          Application
来源:            .NET Runtime
日期:            2020/6/20 6:07:46
事件 ID:         1000
任务类别:          无
级别:            警告
关键字:           经典
用户:            暂缺
计算机:           WIN-MOB4CJQVQTH
描述:
Category: OutIpService.WorkerService.Worker
EventId: 0

the current working directory of the application;G:\xx\src\OutIpService\OutIpService.WorkerService

事件 Xml:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <Provider Name=".NET Runtime" />
    <EventID Qualifiers="0">1000</EventID>
    <Level>3</Level>
    <Task>0</Task>
    <Keywords>0x80000000000000</Keywords>
    <TimeCreated SystemTime="2020-06-19T22:07:46.000000000Z" />
    <EventRecordID>50197</EventRecordID>
    <Channel>Application</Channel>
    <Computer>WIN-MOB4CJQVQTH</Computer>
    <Security />
  </System>
  <EventData>
    <Data>Category: OutIpService.WorkerService.Worker
EventId: 0

the current working directory of the application;G:\xx\src\OutIpService\OutIpService.WorkerService
</Data>
  </EventData>
</Event>

How to setup event log for .NET Core 3.x Worker Service

Overrides the default set and allows information logs to be viewed, edit the appsettings.json file to look like the following:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    },
    "EventLog": {
      "LogLevel": {
        "Default": "Information",
        "Microsoft.Hosting.Lifetime": "Information"
      }
    }
  }
}

 

 

 

2.Run 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

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, lets publish the application

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

Mention

after you call .UseWindowsService(),Don't call AddEventLog again in program.cs, Configure the options in DI rather than passing them in directly:

https://github.com/dotnet/extensions/src/Hosting/WindowsServices/src/WindowsServiceLifetimeHostBuilderExtensions.cs  source

using System;
using System.Runtime.InteropServices;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Hosting.WindowsServices;
using Microsoft.Extensions.Logging.EventLog;

namespace Microsoft.Extensions.Hosting
{
    /// <summary>
    /// Extension methods for setting up WindowsServiceLifetime.
    /// </summary>
    public static class WindowsServiceLifetimeHostBuilderExtensions
    {
        /// <summary>
        /// Sets the host lifetime to WindowsServiceLifetime, sets the Content Root,
        /// and enables logging to the event log with the application name as the default source name.
        /// </summary>
        /// <remarks>
        /// This is context aware and will only activate if it detects the process is running
        /// as a Windows Service.
        /// </remarks>
        /// <param name="hostBuilder">The <see cref="IHostBuilder"/> to operate on.</param>
        /// <returns>The same instance of the <see cref="IHostBuilder"/> for chaining.</returns>
        public static IHostBuilder UseWindowsService(this IHostBuilder hostBuilder)
        {
            if (WindowsServiceHelpers.IsWindowsService())
            {
                // Host.CreateDefaultBuilder uses CurrentDirectory for VS scenarios, but CurrentDirectory for services is c:\Windows\System32.
                hostBuilder.UseContentRoot(AppContext.BaseDirectory);
                hostBuilder.ConfigureLogging((hostingContext, logging) =>
                {
                    logging.AddEventLog();  //here
                })
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddSingleton<IHostLifetime, WindowsServiceLifetime>();
                    services.Configure<EventLogSettings>(settings =>
                    {
                        if (string.IsNullOrEmpty(settings.SourceName))
                        {
                            settings.SourceName = hostContext.HostingEnvironment.ApplicationName;
                        }
                    });
                });
            }

            return hostBuilder;
        }
    }
}

 

 

step 2.create an Run as a Windows Service

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

run the following dotnet command:

dotnet publish -c release

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

you must run cmd as administrators,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=G:\stock\ReadDZHRealTime\src\WinTimerTask\Stockso.WindowsService\bin\release\netcoreapp3.1\publish\Stockso.WindowsService.exe

or

sc.exe create OutIpService.WorkerService DisplayName= "OutIpService.WorkerService" binpath= "G:\stock\ReadDZHRealTime\src\OutIpService\OutIpService.WorkerService\bin\release\netcoreapp3.1\publish\OutIpService.WorkerService.dll --run-as-service"
sc.exe create OutIpService.WorkerService DisplayName= "OutIpService.WorkerService" binpath= "F:\stock\ReadDZHRealTime\src\OutIpService\OutIpService.WorkerService\bin\release\net8.0\publish\OutIpService.WorkerService.dll --run-as-service"

otherwise,you can get error:

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

The service is created successfully, and you can see it in the Services viewer application. From there, you can manually start/stop the service.

Three, start   OutIpService.WorkerService

sc start OutIpService.WorkerService

Create and manage the Windows Service

sc.exe create OutIpService.WorkerService DisplayName= "OutIpService.WorkerService" binpath="F:\stock\ReadDZHRealTime\src\OutIpService\OutIpService.WorkerService\bin\release\net8.0\publish\OutIpService.WorkerService.exe --run-as-service"


sc start OutIpService.WorkerService
sc stop OutIpService.WorkerService
sc delete OutIpService.WorkerService
sc query OutIpService.WorkerService

.Net 8.x  

sc qfailure OutIpService.WorkerService
[SC] QueryServiceConfig2 成功

SERVICE_NAME: OutIpService.WorkerService
        RESET_PERIOD (以秒计)        : 0
        REBOOT_MESSAGE               :
        COMMAND_LINE                 :

https://learn.microsoft.com/en-us/dotnet/core/extensions/windows-service  .net 8.x

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

2.Worker Service sample

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

3.CreateDefaultBuilder(string[] args)