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://docs.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.
The Generic Host can be used with other types of . NET applications, such as Console apps. A host is an object that encapsulates an app's resources and lifetime functionality, such as: Dependency injection (DI)
Starting with the December 2022 servicing update for Visual Studio 2019 16.11, Visual Studio 2019 17.0, and Visual Studio 2022 17.2, the . NET Core 3.1 component in Visual Studio will be changed to out of support and optional.
NET Core 2.2 Lifecycle. . NET Core releases belong to one of two support lifecycles: long term support (LTS) and Current. LTS releases are stable release which receive critical updates and are supported for at least three years.
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With