如何从.Net Core 3制作Windows服务 [英] How to make a Windows service from .Net Core 3
问题描述
最近,我需要将.Net Core 3.0控制台应用程序转换为Windows服务.
Recently I had a need to convert a .Net Core 3.0 console application into a Windows Service.
由于我不需要将此过程移植到Linux,因此我可以省去我在Stackoverflow上看到的涉及.Net Framework,.Net Standard和.Net Core任意组合的多平台解决方案.
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 Stackoverflow that dealt with any combination of .Net Framework, .Net Standard and .Net Core.
Visual Studio 2019即将推出一个工作程序模板.由于它是预发布版本,因此会存在一些潜在的稳定性问题.我无法使用其中的一种参考,因此,在模板稳定之前,我在下面提出的解决方案就足够了.(请参见 https://devblogs.microsoft.com/aspnet/net-core-workers-as-windows-services/)
There is coming up for Visual Studio 2019 a worker template. As it is pre-release, there will be some potential stability issues. I could not get one of the references to work, so the solution I pose below should suffice until the template is stable. (see https://devblogs.microsoft.com/aspnet/net-core-workers-as-windows-services/)
推荐答案
- 首先在Visual Studio 2019中创建.Net Core控制台应用程序.使用前,您需要安装.Net Core 3 SDK.还确保通过在工具"->选项"->预览功能",使用.NET Core SDK的预览"中指定设置来引用.Net Core 3预览
- 将语言版本设置为至少7.1,以支持Main方法的异步任务.(从项目设置->构建->高级->语言设置中访问语言版本)..Net Core 3和Visual Studio 2019支持C#8.0
- 添加Microsoft.Extensions.Hosting和System.ServiceProcess.ServiceController程序包.
现在转到Program.cs并复制以下内容:
Now go to Program.cs and copy the following:
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();
}
}
}
}
此代码将支持交互式调试和生产执行,并运行示例类LoggingService.
This code will support interactive debugging and production execution, and runs the example class 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:
ServiceBaseLifetime.cs:
ServiceBaseLifetime.cs:
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();
}
}
}
ServiceBaseLifetimeHostExtensions.cs:
ServiceBaseLifetimeHostExtensions.cs:
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);
}
}
}
为了维护服务,我使用了"sc"实用程序:要创建:sc创建AdvancedHost binPath ="C:\ temp \ AdvancedHost \ AdvancedHost.exe"其中"AdvancedHost"是服务名称,binPath的值是已编译的可执行文件.
To maintain the service I use the 'sc' utility: To create: sc create AdvancedHost binPath="C:\temp\AdvancedHost\AdvancedHost.exe" where 'AdvancedHost' is the service name and the value for binPath is the compiled executable.
有关状态:sc查询AdvancedHost
For status: sc query AdvancedHost
要开始:sc启动AdvancedHost
To start: sc start AdvancedHost
要停止:sc停止AdvancedHost
To stop: sc stop AdvancedHost
要删除(一旦停止):sc删除AdvancedHost
To delete (once stopped): sc delete AdvancedHost
sc中包含更多功能;只需在命令行上单独输入"sc"即可.sc的结果可以在Windows服务控制台中看到.
There are many more features contained in sc; just type 'sc' alone on the command line. The results of sc can be seen in the services Windows control panel.
这篇关于如何从.Net Core 3制作Windows服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!