Консольное приложение ядра.net с использованием верхней полки

Я создал консольное приложение ядра.net с использованием верхней полки. Но я получил ошибку при запуске приложения с помощью docker (alpine-linux).

Configuration Result:
    [Success] Name MyApp
    [Success] DisplayName MyApp
    [Success] Description My Application
    [Success] ServiceName MyApp
    Topshelf v4.1.0.177, .NET Framework v4.0.30319.42000
    Topshelf.Runtime.Windows.WindowsHostEnvironment Error: 0 : Unable to get parent process (ignored), System.DllNotFoundException: Unable to load shared library 'kernel32.dll' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: Error loading shared library libkernel32.dll: No such file or directory
       at Topshelf.Runtime.Windows.Kernel32.CreateToolhelp32Snapshot(UInt32 dwFlags, UInt32 th32ProcessID)
       at Topshelf.Runtime.Windows.WindowsHostEnvironment.GetParent(Process child)
    Topshelf.HostFactory Error: 0 : The service terminated abnormally, System.PlatformNotSupportedException: ServiceController enables manipulating and accessing Windows services and it is not applicable for other operating systems.
       at System.ServiceProcess.ServiceController.GetServices()
       at Topshelf.Runtime.Windows.WindowsHostEnvironment.IsServiceListed(String serviceName)
       at Topshelf.Hosts.ConsoleRunHost.Run()
       at Topshelf.HostFactory.Run(Action`1 configureCallback)

Как решить эту проблему? Мне нужно запустить консольное приложение в качестве службы Windows

0 ответов

Документация Topshelf довольно конкретна:

Для работы с Topshelf вам потребуется операционная система Windows. Разработчики Topshelf регулярно тестируют на Windows 7 и Windows Server 2008RC2. Хотя он должен работать в Windows Server 2003, если установлен.Net 3.5 sp1.

Хорошая новость заключается в том, что писать демонов Linux проще, чем служб Windows - все, что им нужно, это консольное приложение, в котором вы управляете основным циклом.

Если я правильно понял вашу проблему, вы хотите иметь возможность запускать одну службу как в Windows, так и в Docker. В этом случае кажется, что проще всего будет проверить среду вашей ОС при запуске с помощью чего-то вроде System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform() и либо отложите свою основную работу до Topshelf, либо запустите ее в стиле Linux. Для примера ниже я установилMicrosoft.Extensions.Hostingпакет и решил реализовать IHostedService (который Topshelf может удобно повторно использовать)

public class YourHostedService : IHostedService, IDisposable
{
    private int executionCount = 0;
    private Timer _timer;

    public YourHostedService()
    {
    }

    public Task StartAsync(CancellationToken stoppingToken)
    {
        _timer = new Timer(DoWork, null, TimeSpan.Zero,
            TimeSpan.FromSeconds(5));

        return Task.CompletedTask;
    }

    private void DoWork(object state)
    {
        executionCount++;// this gets called every 5 seconds
    }

    public Task StopAsync(CancellationToken stoppingToken)
    {
        _timer?.Change(Timeout.Infinite, 0);
        return Task.CompletedTask;
    }

    public void Dispose() => _timer?.Dispose();
}

public class Program
{
    public static async Task Main(string[] args)
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            var rc = HostFactory.Run(x =>
            {
                var token = CancellationToken.None;
                x.Service<YourHostedService>(s =>
                {
                    s.ConstructUsing(name => new YourHostedService());
                    s.WhenStarted(tc => tc.StartAsync(token));
                    s.WhenStopped(tc => tc.StopAsync(token));
                });
                x.RunAsLocalSystem();

                x.SetDescription("TopShelf Host");
                x.SetDisplayName("YourHostedService");
                x.SetServiceName("YourHostedService");
            });
        }
        else
        {
            await Host.CreateDefaultBuilder(args)
                .ConfigureServices(builder =>
                {
                    builder.AddHostedService<YourHostedService>();
                })
                .RunConsoleAsync();
        }
    }
}

Больше вдохновения можно сделать здесь.

UPD Так что, похоже, ваш конкретный случай также можно решить, запустив произвольную (в данном случае вашу) программу как службу Windows. В этом случае у вас есть несколько вариантов, которые не связаны с программированием, а скорее с написанием конфигурации:

  1. В собственном инструменте SrvAny компании Microsoft, которая была частью NT Resource Kit: вы в основном установить его в качестве фиктивной службы и редактировать параметр реестра, чтобы указать на.exe
  2. Третий SrvStart инструмента стороны: это один относительно легко подобрать так, и конфигурация подобна выше

Итак, ваше требование - запустить приложение ядра dotnet (какая версия?) В качестве службы Windows.

TopShelf может быть не подходящим инструментом для этого, поскольку он поддерживает.NET Framework 4.0 или Mono, а не ядро ​​dotnet.

Поскольку вы хотите запустить службу Windows, нет смысла публиковать свое приложение как образ Linux Docker! Использоватьsc create а также sc start чтобы вместо этого зарегистрироваться и запустить опубликованный исполняемый файл.

Topshelf - не лучший выбор для.NET Core, потому что.Net Core имеет мощные возможности для сборки Windows Service. Кроме того, TopShelf поддерживает только Windows. См. Примеры:

https://medium.com/@tocalai/create-windows-service-using-net-core-console-application-dc2f278bbe42

https://codeburst.io/create-a-windows-service-app-in-net-core-3-0-5ecb29fb5ad0

Другие вопросы по тегам