[英]How to make a Windows Service from .NET Core 2.1/2.2
Recently I had a need to convert a .NET Core 2.1 or 2.2 console application into a Windows Service.最近我需要将 .NET Core 2.1 或 2.2 控制台应用程序转换为 Windows 服务。
As I didn't have a requirement to port this process to Linux, I could dispense with the multiple platform solutions that I had seen on Stack Overflow that dealt with any combination of .NET Framework, .NET Standard and .NET Core.由于我不需要将此过程移植到 Linux,因此我可以放弃在 Stack Overflow 上看到的处理 .NET Framework、.NET Standard 和 .NET Core 的任意组合的多平台解决方案。
In this post I will describe the steps required to set up a .NET Core 2.1 or 2.2 process as a Windows Service.在本文中,我将描述将 .NET Core 2.1 或 2.2 进程设置为 Windows 服务所需的步骤。
As I have no requirement for Linux, I could look for a solution that was Windows-specific.因为我对 Linux 没有要求,所以我可以寻找特定于 Windows 的解决方案。
A bit of digging turned up some posts from Steve Gordon (thanks,).一些挖掘发现了史蒂夫戈登的一些帖子(谢谢,)。 in particular where he presents the Microsoft.Extensions.Hosting package and Windows hosting (click here for post and here for his GitHub sample).
特别是他展示了 Microsoft.Extensions.Hosting 包和 Windows 托管(单击此处查看帖子,单击此处查看他的 GitHub 示例)。
Here are the steps required:以下是所需的步骤:
Now go to Program.cs and copy the following:现在转到 Program.cs 并复制以下内容:
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace AdvancedHost
{
internal class Program
{
private static async Task Main(string[] args)
{
var isService = !(Debugger.IsAttached || args.Contains("--console"));
var builder = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<LoggingService>();
});
if (isService)
{
await builder.RunAsServiceAsync();
}
else
{
await builder.RunConsoleAsync();
}
}
}
}
This code will support interactive debugging and production execution, and runs the example class LoggingService.此代码将支持交互式调试和生产执行,并运行示例类 LoggingService。
Here is a skeleton example of the service itself:这是服务本身的骨架示例:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Concurrent;
namespace AdvancedHost
{
public class LoggingService : IHostedService, IDisposable
{
public Task StartAsync(CancellationToken cancellationToken)
{
// Startup code
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
// Stop timers, services
return Task.CompletedTask;
}
public void Dispose()
{
// Dispose of non-managed resources
}
}
}
The final two files necessary to complete the project:完成项目所需的最后两个文件:
using Microsoft.Extensions.Hosting;
using System;
using System.ServiceProcess;
using System.Threading;
using System.Threading.Tasks;
namespace AdvancedHost
{
public class ServiceBaseLifetime : ServiceBase, IHostLifetime
{
private readonly TaskCompletionSource<object> _delayStart = new TaskCompletionSource<object>();
public ServiceBaseLifetime(IApplicationLifetime applicationLifetime)
{
ApplicationLifetime = applicationLifetime ?? throw new ArgumentNullException(nameof(applicationLifetime));
}
private IApplicationLifetime ApplicationLifetime { get; }
public Task WaitForStartAsync(CancellationToken cancellationToken)
{
cancellationToken.Register(() => _delayStart.TrySetCanceled());
ApplicationLifetime.ApplicationStopping.Register(Stop);
new Thread(Run).Start(); // Otherwise this would block and prevent IHost.StartAsync from finishing.
return _delayStart.Task;
}
private void Run()
{
try
{
Run(this); // This blocks until the service is stopped.
_delayStart.TrySetException(new InvalidOperationException("Stopped without starting"));
}
catch (Exception ex)
{
_delayStart.TrySetException(ex);
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
Stop();
return Task.CompletedTask;
}
// Called by base.Run when the service is ready to start.
protected override void OnStart(string[] args)
{
_delayStart.TrySetResult(null);
base.OnStart(args);
}
// Called by base.Stop. This may be called multiple times by service Stop, ApplicationStopping, and StopAsync.
// That's OK because StopApplication uses a CancellationTokenSource and prevents any recursion.
protected override void OnStop()
{
ApplicationLifetime.StopApplication();
base.OnStop();
}
}
}
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace AdvancedHost
{
public static class ServiceBaseLifetimeHostExtensions
{
public static IHostBuilder UseServiceBaseLifetime(this IHostBuilder hostBuilder)
{
return hostBuilder.ConfigureServices((hostContext, services) => services.AddSingleton<IHostLifetime, ServiceBaseLifetime>());
}
public static Task RunAsServiceAsync(this IHostBuilder hostBuilder, CancellationToken cancellationToken = default)
{
return hostBuilder.UseServiceBaseLifetime().Build().RunAsync(cancellationToken);
}
}
}
In order to install, run or delete the service I use the 'sc' utility:为了安装、运行或删除我使用“sc”实用程序的服务:
sc create AdvancedHost binPath="C:\temp\AdvancedHost\AdvancedHost.exe"
where AdvancedHost
is the service name and the value for binPath
is the compiled executable.其中
AdvancedHost
是服务名称, binPath
的值是已编译的可执行文件。
Once the service is created, to start:创建服务后,开始:
sc start AdvancedHost
To stop:停止:
sc stop AdvancedHost
And finally to delete (once stopped):最后删除(一旦停止):
sc delete AdvancedHost
There are many more features contained in sc; sc 中包含更多功能; just type 'sc' alone on the command line.
只需在命令行中单独输入“sc”。
The results of sc can be seen in the services Windows control panel. sc 的结果可以在服务 Windows 控制面板中看到。
You no longer need to copy-paste a lot of code to do it.您不再需要复制粘贴大量代码来完成它。 All you need is to install the package Microsoft.Extensions.Hosting.WindowsServices
您只需要安装软件包Microsoft.Extensions.Hosting.WindowsServices
Then:然后:
UseWindowsService()
to the HostBuilder.UseWindowsService()
附加到 HostBuilder。 This will also configure your application to use the EventLog logger.Microsoft.NET.Sdk.Worker
( <Project Sdk="Microsoft.NET.Sdk.Worker">
).Microsoft.NET.Sdk.Worker
( <Project Sdk="Microsoft.NET.Sdk.Worker">
)。<OutputType>Exe</OutputType>
)<OutputType>Exe</OutputType>
)<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
to the project file.<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
附加到项目文件。 Debug your service like a regular console application, and then run dotnet publish
, sc create...
, etc.像常规控制台应用程序一样调试您的服务,然后运行
dotnet publish
、 sc create...
等。
That's it.而已。 This also works for .NET Core 3.0/3.1.
这也适用于 .NET Core 3.0/3.1。 Read more here .
在这里阅读更多。
The minimal code example is shown below.最小代码示例如下所示。
<Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup>
<OutputType>Exe</OutputType>
<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="3.1.3" />
</ItemGroup>
</Project>
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace NetcoreWindowsService
{
class Program
{
static void Main()
{
new HostBuilder()
.ConfigureServices(services => services.AddHostedService<MyService>())
.UseWindowsService()
.Build()
.Run();
}
}
}
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;
namespace NetcoreWindowsService
{
internal class MyService : IHostedService
{
private readonly ILogger<MyService> _logger;
public MyService(ILogger<MyService> logger) => _logger = logger;
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("The service has been started");
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("The service has been stopped");
return Task.CompletedTask;
}
}
}
Top shelf has been a good "framework" for Windows Services. Top shelf 一直是 Windows 服务的良好“框架”。
It provides good functionality for the routine stuff that all windows services share.它为所有 Windows 服务共享的常规内容提供了良好的功能。
Especially "install".特别是“安装”。
The basics are:基础知识是:
https://www.nuget.org/packages/Topshelf/ https://www.nuget.org/packages/Topshelf/
Note the nuget above can be run under NetStandard2.0.注意上面的nuget可以在NetStandard2.0下运行。
Now below.现在在下面。 You can create MyWindowsServiceExe.csproj.. and code it as an Exe/2.1 or Exe/3.1 (shown when you open up the csproj).
您可以创建 MyWindowsServiceExe.csproj.. 并将其编码为 Exe/2.1 或 Exe/3.1(打开 csproj 时显示)。 Note that 2.2 is not Long Term Support anymore and I would avoid writing new code to 2.2.
请注意,2.2 不再是长期支持,我会避免为 2.2 编写新代码。 (off topic, but that link is https://dotnet.microsoft.com/platform/support/policy/dotnet-core )
(题外话,但该链接是https://dotnet.microsoft.com/platform/support/policy/dotnet-core )
public class LoggingService : TopShelf.ServiceControl
{
private const string logFileFullName = @"C:\temp\servicelog.txt";
private void MyLogMe(string logMessage)
{
Directory.CreateDirectory(Path.GetDirectoryName(logFileFullName));
File.AppendAllText(logFileFullName, DateTime.UtcNow.ToLongTimeString() + " : " + logMessage + Environment.NewLine);
}
public bool Start(HostControl hostControl)
{
MyLogMe("Starting");
return true;
}
public bool Stop(HostControl hostControl)
{
MyLogMe("Stopping");
return true;
}
}
static void Main(string[] args)
{
HostFactory.Run(x =>
{
x.Service<LoggingService>();
x.EnableServiceRecovery(r => r.RestartService(TimeSpan.FromSeconds(333)));
x.SetServiceName("MyTestService");
x.StartAutomatically();
}
);
}
and build/publish it to windows:并将其构建/发布到 Windows:
dotnet publish -r win-x64 -c Release
and then the helper methods I mentioned然后是我提到的辅助方法
MyWindowsServiceExe.exe install安装MyWindowsServiceExe.exe
(now check windows-services under control panel to see it installed) (check "if crash, what should I do" tab as well). (现在检查控制面板下的 windows-services 以查看它是否已安装)(同时检查“如果崩溃,我应该做什么”选项卡)。
and finally (another helper), you can STOP the the windows-service, you can run it from the command line (outside of windows-services) This is my favorite for debugging.最后(另一个助手),你可以停止 windows 服务,你可以从命令行运行它(在 windows 服务之外)这是我最喜欢的调试方式。
MyWindowsServiceExe.exe start MyWindowsServiceExe.exe 启动
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.