Building a basic Windows Service that does some long-running background work is trivial, using .NET's UseWindowsService() (from the Platform Extensions package Microsoft.Extensions.Hosting.WindowsServices) and Microsoft.Extensions.Hosting.BackgroundService from Microsoft.Extensions.Hosting.Abstractions.
Running as a Windows Service and running BackgroundServices are two separate things though, and they are not connected in any way. A non-service console app can run background services, and so can and do web applications. Each of those are different hosting environments, with their own lifetimes.
This project exists of a few classes that make building reliable Windows Services easier, to gap this disconnect.
The following improvements are included in this library:
OnStart()can fail because of invalid service configuration, quit the application when that happens (by kmcclellan).- On consumer OS Windows 10+, shutting down the computer will actually hibernate the OS. Services won't get another
OnStart()call when the computer starts again, nor will your background services be notified. Now they will. - It also can notify your BackgroundServices about user session changes, i.e. logon, logoff and others.
- When an exception occurs during your BackgroundService's lifetime, .NET Platform Extensions < 6 didn't stop the application host. Now it does, but it doesn't report an error to the Service Control Manager. With this extension, it does, as well as setting a process exit code: 13 in both cases ("invalid data").
Through NuGet:
> Install-Package CodeCaster.WindowsServiceExtensions
These methods from this package allow your IHostedServices to tell the Windows Service Control Manager about errors, and respond to Windows Service events relating to sessions (user logon/logoff) and power state (shutdown/hibernate/resume):
- On your Host Builder, call
UseWindowsServiceExtensions()instead ofUseWindowsService(). - Instead of letting your service inherit
BackgroundService, inherit fromCodeCaster.WindowsServiceExtensions.WindowsServiceBackgroundService. - Implement
protected Task TryExecuteAsync(CancellationToken stoppingToken)instead ofExecuteAsync(CancellationToken stoppingToken). - Implement the method
public override bool OnPowerEvent(PowerBroadcastStatus powerStatus) { ... }and do your thing when it's called with a certain status. - Implement the method
public override bool OnSessionChange(SessionChangeDescription changeDescription) { ... }and do your thing when it's called with a certain status.
Do note that the statuses received can vary. You get either ResumeSuspend, ResumeAutomatic or both reported to OnPowerEvent(), never neither, after a machine wake, reboot or boot.
For examples and more specific documentation, see https://codecasternl.github.io/WindowsServiceExtensions/.
If you're one of the souls that use this library (who are you?), you'll want to upgrade to v3.0 after upgrading your projects to .NET 6.
Changes:
- The DI extension method
IHostBuilder.UsePowerEventAwareWindowsService()is now calledUseWindowsServiceExtensions()because we do more than power events now. - The long-running hosted service base class
CodeCaster.WindowsServiceExtensions.PowerEventAwareBackgroundServicewas renamed toCodeCaster.WindowsServiceExtensions.Service.WindowsServiceBackgroundService, because the former didn't have enough "Service" in its name. - Instead of
BackgroundService.ExecuteAsync(), which is now sealed, overrideWindowsServiceBackgroundService.TryExecuteAsync()to do your long-running work.
Extended upgrading docs: see https://codecasternl.github.io/WindowsServiceExtensions/upgrading-v2-v3.
Please file an issue or PR. Even if you use this and are happy with it.