os:windows server 2012 R2
.net core:net core 3.1.1 .net 8.x
Table of Contents
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
2.Worker Service sample