Skip to content

Service registration

This library registers no services of its own — it exposes two startup base classes a consumer inherits (ServiceProgramRunnerBase for the program entry point, ServiceWorker<T> for the recurring task loop) and resolves four services from the DI container that only SAIF.NetCore.ServiceExtensions's RegisterForWindowsService/RegisterForWindowsService<T> actually registers; a consuming Windows Service application must reference and call that companion method, or supply the same contracts itself through manual registration.

Registration extension catalog

This library defines no IServiceCollection/IHostBuilder extension methods itself. The extension methods below are owned and shipped by SAIF.NetCore.ServiceExtensions; they are documented here because this library's startup base classes and ServiceWorker<T> require their output to be present in the DI container at runtime. See SAIF.NetCore.ServiceExtensions overview for that library's own documentation. Using RegisterForWindowsService/RegisterForWindowsService<T> is the recommended way to satisfy those runtime contracts, but it is not the only way: ServiceWorker<T> and ServiceProgramRunnerBase only require that IWindowsServiceErrorHandler, ISaifWindowsServiceLogService, IEnvironmentClient, and IHttpJsonClient be resolvable from the container, however they get there — an equivalent set of manual registrations satisfies the same contracts without calling this specific extension method.

Extension method Hosting context Parameters Source
RegisterForWindowsService<T>(this IServiceCollection services, bool registerSecureEnvironmentClient = true) where T : class worker (Windows service) registerSecureEnvironmentClient (default true): when true, calls RegisterSecureEnvironmentClient(typeof(T)); when false, calls RegisterEnvironmentClient() (non-secure, registers ISystemHashService as a factory returning null). Always also registers ISaifWindowsServiceLogService, IWindowsServiceErrorHandler, and calls RegisterDBConnectionClient(). src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cs
RegisterForWindowsService(this IServiceCollection services) worker (Windows service) No parameters; delegates to RegisterForWindowsService<object>(false) — always takes the non-secure EnvironmentClient path. src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cs

Overload-selection caveat: RegisterDBConnectionClient() is called unconditionally by both overloads, always registering IDBConnectionClient as a lazy singleton factory. That factory lambda (in SAIF.NetCore.ServiceExtensions, not inside ConnectionClient) constructs its own SystemHashService(typeof(ConnectionClient).Assembly) — it does not use the container-registered ISystemHashService — gets its hash, and calls IEnvironmentClient.GetSecureSetting to retrieve and split the connection credential before calling ConnectionClient.SetupClientCredentials. On the non-secure path — either the parameterless RegisterForWindowsService() overload, or RegisterForWindowsService<T>(false) — IEnvironmentClient resolves to the non-secure BaseEnvironmentClient, whose GetSecureSetting throws EnvironmentClientException ("Operation not allowed! This application is restricted from retrieving secure settings.") rather than failing with a null-reference error; the registered-but-unused null ISystemHashService factory is not involved in this failure. Prefer the generic overload with its true default (or pass true explicitly) whenever IDBConnectionClient will be used.

Service registration catalog

These are the registrations made by the companion SAIF.NetCore.ServiceExtensions.RegisterForWindowsService<T>/RegisterForWindowsService calls this library depends on at runtime — none of them are registered by this library itself. A consumer may instead register the same contracts manually if it does not want the convenience call.

Service type Implementation Lifetime Registered by Condition Source
IEnvironmentClient (+ ISystemWrapper, IHostResolver, IHttpJsonClient transient, ISystemHashService) SecureEnvironmentClient / BaseEnvironmentClient Singleton (IHttpJsonClient transient) RegisterSecureEnvironmentClient(typeof(T)) / RegisterEnvironmentClient() Gated by registerSecureEnvironmentClient; the non-generic RegisterForWindowsService() overload passes false, registering ISystemHashService as a factory returning null. src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cs
ISaifWindowsServiceLogService SaifWindowsServiceLog Singleton RegisterForWindowsService<T> Always src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cs
IWindowsServiceErrorHandler WindowsServiceErrorHandler Singleton RegisterForWindowsService<T> Always src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cs
IDBConnectionClient factory -> ConnectionClient (in SAIF.NetCore.DbConnectionClient) with secure credentials Singleton RegisterDBConnectionClient() Always src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cs; src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs

Startup base classes

Base classes a consuming application inherits to bootstrap its host.

Base class Inherits Consumer type Must implement May override Source
ServiceProgramRunnerBase object Windows Service entry point (Program) None (no abstract members) Run(string[]): creates the host once, then calls IHost.Run(). Create(string[]): builds the host, applies the optional delay, calls Configure. CreateHostBuilder(string[]): CreateDefaultBuilder + re-added appsettings.json + environment variables + UseWindowsService(). ConfigureErrorHandler(IWindowsServiceErrorHandler): empty by default. Configure(IHost): runs the error-handler hook, then ConfigureLogger. ConfigureLogger(IHost): calls ISaifWindowsServiceLogService.Configure(env, http). src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceProgramRunnerBase.cs
ServiceWorker<T> (where T : IServiceTaskRunner) Microsoft.Extensions.Hosting.BackgroundService One consumer worker class per scheduled task None (no abstract members) ExecuteAsync (override): fixed-delay loop, immediate first run. RunTaskAsync: try/catch around TaskRunner.Run. HandleTaskError: exemption check, error-handler call, host stop. BuildErrorMessage: standard error-message text. Non-virtual: IsExceptionExemptFromShutdown. src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceWorker.cs

Feature flags

Properties a consumer overrides, and environment variables a base class reads, that change registration or middleware behavior. Environment variables are also listed in Configuration.

Name Kind Default Effect Source
TaskDelayMilliseconds Property (ServiceWorker<T>) 3000 Delay after each task run, before the next iteration. src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceWorker.cs
ShutdownTimeoutSeconds Property (ServiceWorker<T>) 30 Graceful-stop timeout passed to ServiceHost.StopAsync on a fail-stop error. src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceWorker.cs
DelayStart Environment variable / configuration key (process) unset (no delay) Blocks startup for N ms before the configuration hooks and IHost.Run(). src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceProgramRunnerBase.cs

Hosted services and health checks

Type Kind Registered by Behavior Source
ServiceWorker<T> (abstract; consumer subclasses) BackgroundService The consumer, with services.AddHostedService<TWorker>() — this library does not register it Runs T.Run(stoppingToken) immediately, then every TaskDelayMilliseconds after completion. Catches all errors, reports them to IWindowsServiceErrorHandler, and stops the host unless the exception's exact runtime type is registered as shutdown-exempt and its predicate allows it. src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceWorker.cs

There are no health checks or ping endpoints.

Required-but-not-registered services

Services this library's types resolve that none of its own methods add. The consuming application, or another library, must register them — in practice, by referencing SAIF.NetCore.ServiceExtensions and calling RegisterForWindowsService/RegisterForWindowsService<T>.

Service type Consumer Expected source
IServiceTaskRunner (concrete T) ServiceWorker<T> constructor The consumer app (e.g. AddTransient<IMyRunner, MyRunner>())
IWindowsServiceErrorHandler ServiceWorker<T> constructor; ServiceProgramRunnerBase.Configure (GetRequiredService) SAIF.NetCore.ServiceExtensions's RegisterForWindowsService → SAIF.NetCore.ErrorHandler's WindowsServiceErrorHandler (singleton)
ISaifWindowsServiceLogService ServiceProgramRunnerBase.ConfigureLogger RegisterForWindowsService → SAIF.NetCore.Logging's SaifWindowsServiceLog (singleton)
IEnvironmentClient ServiceProgramRunnerBase.ConfigureLogger RegisterForWindowsService → SAIF.NetCore.EnvironmentClient's BaseEnvironmentClient/SecureEnvironmentClient (singleton)
IHttpJsonClient ServiceProgramRunnerBase.ConfigureLogger RegisterForWindowsService → SAIF.NetCore.HttpClients's HttpJsonClient (transient)
IConfiguration ServiceProgramRunnerBase.DelayStartup Generic Host (always registered automatically)

Sources

  • src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService.csproj
  • src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceProgramRunnerBase.cs
  • src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceWorker.cs
  • src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cs
  • src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs