Small, dependency-light utilities for
Microsoft.Extensions.Hosting that remove
the boilerplate around shared-instance registrations, exit codes on shutdown and fixed-rate background work.
- Multi-interface registration. Register one implementation under several service types without creating duplicate instances.
- Hosted services you can talk to.
AddHostedServiceoverloads make the running hosted service resolvable through its own interfaces. - Host control with exit codes. Stop the generic host gracefully while setting the process exit code.
- Fixed-cadence background services. Run background work on a monotonic schedule that never drifts and never overlaps.
dotnet add package Invex.Extensions.HostingThe package targets .NET 10 and .NET Standard 2.0. The .NET Standard build can be consumed by
compatible runtimes, including .NET Framework 4.8 and older .NET versions. The only runtime dependency is
Microsoft.Extensions.Hosting.Abstractions.
using Invex.Extensions.Hosting;
using Invex.Extensions.Hosting.Control;
using Invex.Extensions.Hosting.Service;
using Microsoft.Extensions.Hosting;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostControl();
builder.Services.AddHostedService<IWorkerStatus, Worker>();
await builder.Build().RunAsync();
public interface IWorkerStatus
{
bool IsBusy { get; }
}
public sealed class Worker(IHostControl hostControl) : CycleBackgroundService, IWorkerStatus
{
public bool IsBusy { get; private set; }
protected override int CycleCadenceMs => 5_000;
protected override async Task ExecuteCycleAsync(CancellationToken stoppingToken)
{
IsBusy = true;
try
{
await DoWorkAsync(stoppingToken);
}
catch (FatalException)
{
hostControl.StopApplication(exitCode: 1);
}
finally
{
IsBusy = false;
}
}
private static Task DoWorkAsync(CancellationToken stoppingToken) => Task.CompletedTask;
}
public sealed class FatalException : Exception;Worker is registered once. It is both the running IHostedService and the instance returned when
another component injects IWorkerStatus.
ServiceCollectionExtensions provides AddSingleton and AddScoped overloads for two to five
service types, and AddHostedService overloads for one to five:
services.AddSingleton<IFoo, IBar, MyService>();
services.AddScoped<IRequestState, IRequestMetrics, RequestState>();
services.AddHostedService<IQueueMonitor, QueueWorker>();The implementation type is registered once and each listed service type forwards to it, so resolving any of
them returns the same object (per scope for scoped registrations). The hosted-service overloads also register
that instance as IHostedService. See Multi-Interface Registration.
Register IHostControl once with AddHostControl(), then inject it wherever you would use
IHostApplicationLifetime:
builder.Services.AddHostControl();
public sealed class FailureHandler(IHostControl hostControl)
{
public void StopForFailure() => hostControl.StopApplication(exitCode: 2);
}StopApplication(exitCode) assigns Environment.ExitCode, requests graceful shutdown and returns
immediately. See Host Control.
Derive from CycleBackgroundService and implement two members:
public sealed class MetricsFlusher(IMetricsBuffer buffer) : CycleBackgroundService
{
protected override int CycleCadenceMs => 10_000;
protected override Task ExecuteCycleAsync(CancellationToken stoppingToken) =>
buffer.FlushAsync(stoppingToken);
}Cycles are scheduled from the previous scheduled start, never overlap, and catch up back-to-back after an overrun. See Cycle Background Service.
Full documentation: https://invex-games.github.io/hosting-extensions/
| Guide | Contents |
|---|---|
| Introduction | What the library is for, key concepts and design principles |
| Getting Started | Installation, supported frameworks and a guided example |
| Multi-Interface Registration | Shared-instance DI registrations |
| Host Control | Graceful shutdown and exit-code behavior |
| Cycle Background Service | Fixed-cadence scheduling, shutdown and errors |
| API Reference | Complete public API |
The repository requires the .NET 10 SDK selected by global.json. From the repository root:
dotnet build Invex.Extensions.Hosting.slnx
dotnet test Invex.Extensions.Hosting.slnxThe documentation site is built with DocFX through the Atom build in _atom/:
atom BuildDocs # build the site into _site/
atom ServeDocs # build and serve it locallyMIT © Declan Smith