#if NET461 using System; using System.ServiceProcess; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; namespace GenericHostSample { public static class ServiceBaseLifetimeHostExtensions { public static IHostBuilder UseServiceBaseLifetime(this IHostBuilder hostBuilder) { return hostBuilder.ConfigureServices((hostContext, services) => services.AddSingleton()); } public static Task RunAsServiceAsync(this IHostBuilder hostBuilder, CancellationToken cancellationToken = default) { return hostBuilder.UseServiceBaseLifetime().Build().RunAsync(cancellationToken); } } public class ServiceBaseLifetime : ServiceBase, IHostLifetime { private TaskCompletionSource _delayStart = new TaskCompletionSource(); public ServiceBaseLifetime(IApplicationLifetime applicationLifetime) { ApplicationLifetime = applicationLifetime ?? throw new ArgumentNullException(nameof(applicationLifetime)); } private IApplicationLifetime ApplicationLifetime { get; } public Task WaitForStartAsync(CancellationToken cancellationToken) { cancellationToken.Register(() => _delayStart.TrySetCanceled()); ApplicationLifetime.ApplicationStopping.Register(Stop); new Thread(Run).Start(); // Otherwise this would block and prevent IHost.StartAsync from finishing. return _delayStart.Task; } private void Run() { try { Run(this); // This blocks until the service is stopped. _delayStart.TrySetException(new InvalidOperationException("Stopped without starting")); } catch (Exception ex) { _delayStart.TrySetException(ex); } } public Task StopAsync(CancellationToken cancellationToken) { Stop(); return Task.CompletedTask; } // Called by base.Run when the service is ready to start. protected override void OnStart(string[] args) { _delayStart.TrySetResult(null); base.OnStart(args); } // Called by base.Stop. This may be called multiple times by service Stop, ApplicationStopping, and StopAsync. // That's OK because StopApplication uses a CancellationTokenSource and prevents any recursion. protected override void OnStop() { ApplicationLifetime.StopApplication(); base.OnStop(); } } } #endif