.net core console application using TopShelf
Asked Answered
C

3

5

I have created a .net core console application using TopShelf. But I got an error when running the application using 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)

How to solve this issue? I need to run my console application as a windows service

Causey answered 8/5, 2019 at 9:32 Comment(2)
if you want to run console application as a windows service this link might help you.Karalee
Wrong OS, this can only work on Windows. Duplicate is here. Linux alternative is here.Genevagenevan
B
5

The Topshelf documentation is pretty specific:

To work with Topshelf you will need to be running on a Windows operating system. The developers of Topshelf regulary test on Windows 7 and Windows Server 2008RC2. Though it should still work on Windows Server 2003, as long as .Net 3.5 sp1 is installed.

The good news is that writing Linux daemons is easier than Windows Services - all they have to be is basically a console application where you control the main loop.

If I got your problem statement correctly, you want to be able to run one service both in Windows and in Docker. In this case it seems the easiest way will be to examine your OS environment on start up with something like System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform() and either defer your main work to Topshelf or run it Linux-style. For the example below I installed Microsoft.Extensions.Hosting package and opted for implementing an IHostedService (which Topshelf can conveniently reuse)

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();
        }
    }
}

More inspiration can be drawn from here.

UPD So it seems your particular case can also be solved by running arbitrary (well, in this case your) program as Windows service. In this case you've got some options that don't involve programming but rather config writing:

  1. The Microsoft's own tool SrvAny that's been part of NT Resource Kit: you basically install it as a dummy service and edit the registry setting to point to your .exe
  2. A 3rd party tool SrvStart: this one's relatively easy to pick up as well, and config is similar to the above
Blakeley answered 17/12, 2019 at 1:11 Comment(0)
M
1

So your requirement is to run a dotnet core (which version?) application as a windows service.

TopShelf might not be the right tool for this, as it supports .NET Framework 4.0 or Mono, not dotnet core.

Since you want to run a windows service, it does not make any sense to publish your app as a Linux Docker image! Use sc create and sc start to register and start your published executable instead.

Mcdowell answered 12/12, 2019 at 6:41 Comment(0)
D
0

Topshelf is not a good choice for .NET Core because .Net Core has powerful facilities for build Windows Service. Furthermore, TopShelf is only supporting Windows. See Examples:

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

Dumbfound answered 18/12, 2019 at 13:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.