Darthg8r
Darthg8r

Reputation: 12685

NetCore 2.1 Generic Host as a service

I'm trying to build a Windows Service using the latest Dotnet Core 2.1 runtime. I'm NOT hosting any aspnet, I do not want or need it to respond to http requests.

I've followed the code found here in the samples: https://github.com/aspnet/Docs/tree/master/aspnetcore/fundamentals/host/generic-host/samples/2.x/GenericHostSample

I've also read this article: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-2.1

The code works great when run inside of a console window using dotnet run. I need it to run as a windows service. I know there's the Microsoft.AspNetCore.Hosting.WindowsServices, but that's for the WebHost, not the generic host. We'd use host.RunAsService() to run as a service, but I don't see that existing anywhere.

How do I configure this to run as a service?

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace MyNamespace
{
    public class Program
    {


        public static async Task Main(string[] args)
        {
            try
            {
                var host = new HostBuilder()
                    .ConfigureHostConfiguration(configHost =>
                    {
                        configHost.SetBasePath(Directory.GetCurrentDirectory());
                        configHost.AddJsonFile("hostsettings.json", optional: true);
                        configHost.AddEnvironmentVariables(prefix: "ASPNETCORE_");
                        configHost.AddCommandLine(args);
                    })
                    .ConfigureAppConfiguration((hostContext, configApp) =>
                    {
                        configApp.AddJsonFile("appsettings.json", optional: true);
                        configApp.AddJsonFile(
                            $"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json",
                            optional: true);
                        configApp.AddEnvironmentVariables(prefix: "ASPNETCORE_");
                        configApp.AddCommandLine(args);
                    })
                    .ConfigureServices((hostContext, services) =>
                    {
                        services.AddLogging();
                        services.AddHostedService<TimedHostedService>();
                    })
                    .ConfigureLogging((hostContext, configLogging) =>
                    {
                        configLogging.AddConsole();
                        configLogging.AddDebug();

                    })

                    .Build();

                await host.RunAsync();
            }
            catch (Exception ex)
            {



            }
        }


    }

    #region snippet1
    internal 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();
        }
    }
    #endregion
}

EDIT: I repeat, this is not to host an ASP.NET Core app. This is a generic hostbuilder, not a WebHostBuilder.

Upvotes: 10

Views: 7191

Answers (3)

Dejan Stojanović
Dejan Stojanović

Reputation: 119

I hope you found the solution for this problem.

In my case I used generic host (introduced in 2.1) for such purpose and then just wrap it up with systemd to run it as a service on Linux host.

I wrote a small article about it https://dejanstojanovic.net/aspnet/2018/june/clean-service-stop-on-linux-with-net-core-21/

I hope this helps

Upvotes: 2

Colin Bull
Colin Bull

Reputation: 969

As others have said you simply need to reuse the code that is there for the IWebHost interface here is an example.

public class GenericServiceHost : ServiceBase
{
    private IHost _host;
    private bool _stopRequestedByWindows;

    public GenericServiceHost(IHost host)
    {
        _host = host ?? throw new ArgumentNullException(nameof(host));
    }

    protected sealed override void OnStart(string[] args)
    {
        OnStarting(args);

        _host
            .Services
            .GetRequiredService<IApplicationLifetime>()
            .ApplicationStopped
            .Register(() =>
            {
                if (!_stopRequestedByWindows)
                {
                    Stop();
                }
            });

        _host.Start();

        OnStarted();
    }

    protected sealed override void OnStop()
    {
        _stopRequestedByWindows = true;
        OnStopping();
        try
        {
            _host.StopAsync().GetAwaiter().GetResult();
        }
        finally
        {
            _host.Dispose();
            OnStopped();
        }
    }

    protected virtual void OnStarting(string[] args) { }

    protected virtual void OnStarted() { }

    protected virtual void OnStopping() { }

    protected virtual void OnStopped() { }
}

public static class GenericHostWindowsServiceExtensions
{
    public static void RunAsService(this IHost host)
    {
        var hostService = new GenericServiceHost(host);
        ServiceBase.Run(hostService);
    }
}

Upvotes: 10

John
John

Reputation: 736

IHostedService if for [asp.net core] backendjob, if u want to build a windows service on .net core, u should reference this package System.ServiceProcess.ServiceController, and use ServiceBase as base class. (you can also start from a .net framework windows service and then change the .csproj file)


edit: please see this doc and this code https://github.com/aspnet/Hosting/blob/dev/src/Microsoft.AspNetCore.Hosting.WindowsServices/WebHostWindowsServiceExtensions.cs. To create a windows service ServiceBase for manage your IHost

Upvotes: 0

Related Questions