BetterHostedServices 1.0.0
See the version list below for details.
dotnet add package BetterHostedServices --version 1.0.0
NuGet\Install-Package BetterHostedServices -Version 1.0.0
<PackageReference Include="BetterHostedServices" Version="1.0.0" />
paket add BetterHostedServices --version 1.0.0
#r "nuget: BetterHostedServices, 1.0.0"
// Install BetterHostedServices as a Cake Addin #addin nuget:?package=BetterHostedServices&version=1.0.0 // Install BetterHostedServices as a Cake Tool #tool nuget:?package=BetterHostedServices&version=1.0.0
Better Hosted Services
This projects is out to solve some limitations with ASP.NET Core's IHostedService
and BackgroundService
.
Problem 1. IHostedService is not good for long running tasks.
Creating an IHostedService
with a long-running task, will delay application startup.
A class like this will never let the application start.
public class MyHostedService: IHostedService
{
public async Task StartAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
// Do some stuff here
}
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
Problem 2. BackgroundServices fail silently if an error occurs
Microsoft recommends extending from BackgroundService
for long running tasks.
However BackgroundServices fails silently if an uncaught error occurs.
This example will not throw an error, but simply fail silently.
public class YieldingAndThenCrashingCriticalBackgroundService: CriticalBackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await Task.Yield(); // Or some other async work
throw new Exception("Oh no something really bad happened");
}
}
You'll simply never know this error happened. We can do better.
Problem 3. HostedServices are not part of the default DI container
If you want to interact with a HostedService from a controller or another service, you're out of luck.
They're completely separate. There's no built-in way to get a reference to a running IHostedService
Introducing BetterHostedServices
BetterHostedServices is a tiny library (<200 lines of code not including tests) that solves some of these issues.
CriticalBackgroundService
It introduces a class you can inherit from: CriticalBackgroundService
- if an uncaught error happens in a CriticalBackgroundService
it will log it and stop the application
You can use it like this: Inherit from the CriticalBackgroundService
public class YieldingAndThenCrashingBackgroundService: BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await Task.Yield(); // Or some other async work
throw new Exception("Oh no something really bad happened");
}
}
Add AddBetterHostedServices()
and your hosted service inside Startup.cs
's ConfigureServices
method.
services.AddBetterHostedServices();
services.AddHostedService<YieldingAndThenCrashingCriticalBackgroundService>();
That's it! Your CriticalBackgroundService now stops the application if an error happens
Customizing error handling
If you need to customize error logging or handle the error in another way, you can override the OnError
method.
public class YieldingAndThenCrashingCriticalBackgroundService : CriticalBackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await Task.Yield(); // Hand over control explicitly, to ensure this behaviour also works
throw new Exception("Crash after yielding");
}
protected override void OnError(Exception exceptionFromExecuteAsync)
{
// Custom logging here
this._applicationEnder.ShutDownApplication(); // or simply call base.OnError
}
public YieldingAndThenCrashingCriticalBackgroundService(IApplicationEnder applicationEnder) : base(applicationEnder)
{
}
}
AddHostedServiceAsSingleton
Occasionally you might want to interact with a Hosted Service from the
rest of your application. You can do this via the AddHostedServiceAsSingleton
method on the IServiceCollection
services.AddHostedServiceAsSingleton<ISomeBackgroundService, SomeBackgroundService>();
After that, you can inject them via the DI container just like any ordinary singleton.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Extensions.Hosting (>= 3.1.8)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.