我有一个用C#编写的Windows服务。应用程序的“大脑”位于名为Driver
的类中。此类异步启动一堆线程来执行许多操作。这段代码中没有任何“阻塞”。驱动程序负责启动这些线程,侦听特定事件并在这些事件上停止线程。
这时,我已将此代码包装为Windows服务。 OnStart
,OnStop
等方法只是此类的包装。 Windows服务可以按照我的意愿运行。但是,现在,我想在Docker容器中运行此代码。我的问题是,如何修改此代码以使其成为一个长期运行的过程,而不是Windows服务。
我最初的想法是将代码包装在控制台应用程序中。然后,将代码从OnStart
移动到Console应用程序的主体。在该代码之后,我将只有一个while(true){}
语句以使控制台应用程序保持活动状态。但是,这感觉像是黑客。
这种方法是黑客吗?或者,是否有“真正的”方法来做到这一点?如果是这样,在Docker中具有长期运行的C#应用程序的推荐方法是什么?
答案 0 :(得分:3)
使用dotnet core 2.1,您还可以在Microsoft.Extensions.Hosting提供的控制台应用程序中使用aspnet已知的IHostedService。结合使用C#> = 7.1(检查项目设置),在这里可以使用异步Main方法,您的代码将如下所示:
static async Task Main(string[] args)
{
var builder = new HostBuilder(); // from Microsoft.Extensions.Hosting
builder.ConfigureServices(s => s.AddSingleton<IHostedService, YourImplementation>());
await builder.RunConsoleAsync();
}
答案 1 :(得分:1)
托管进程(例如Windows服务)比在紧密循环(while(true) {}
)中运行的控制台应用程序更好。由于您打算在Docker容器中运行它,因此建议您查看以.Net Core为目标的AspNet Core,以便可以使用Linux基本映像(映像大小较小)。 AspNet Core提供了一个Web服务器(Kestrel),在这种情况下,它将作为托管过程。
要在AspNet Core中运行长时间运行的任务,请查看Asp.Net core long running task。
答案 2 :(得分:1)
由于您希望将应用程序作为Docker容器运行,因此我想您也希望在Linux上运行它。然后,我认为您可以将代码定位到支持在Windows和Linux(以及Mac)上运行的.NET Core。
有一个名为Microsoft.Extensions.Hosting
的软件包,它是asp.net核心和dotnet核心控制台应用程序的宿主和启动基础结构,它有助于管理整个生命周期的过程。它的ConsoleLifetime
类将处理在名为IHostedService
的接口中定义的常规乘法启动/停止方法。
您只需要实现自己的IHostedService
(或从BackgroundService
类继承)并将其添加到ConfigureServies
中的宿主上下文中即可。
这是一个示例托管服务:
public class TimedHostedService : IHostedService, IDisposable
{
private readonly ILogger _logger;
private Timer _timer;
public TimedHostedService(ILogger<TimedHostedService> logger)
{
_logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is starting.");
_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromSeconds(5));
return Task.CompletedTask;
}
private void DoWork(object state)
{
_logger.LogInformation("Timed Background Service is working.");
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is stopping.");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
然后修改您的主要方法:
public class Program
{
public static async Task Main(string[] args)
{
var hostBuilder = new HostBuilder()
// Add configuration, logging, ...
.ConfigureServices((hostContext, services) =>
{
// Add your services with depedency injection.
services.AddSingleton<IHostedService, TimedHostedService>();
});
await hostBuilder.RunConsoleAsync();
}
}