Configuration settings¶
This library reads exactly one configuration key directly, DelayStart, through IConfiguration. Its larger configuration impact is architectural: it defines the configuration-source stack for every Windows Service built on ServiceProgramRunnerBase, re-appending appsettings.json and unprefixed environment variables after the Generic Host defaults, which inverts standard .NET precedence. At startup it also triggers the Environment API reads of the resolved ISaifWindowsServiceLogService, a transitive dependency.
Configuration retrieval methods¶
| Method | Class / Interface | Namespace | Usage pattern |
|---|---|---|---|
IConfiguration.GetValue<int?>(key) |
IConfiguration, resolved from IHost.Services with GetService |
Microsoft.Extensions.Configuration (+ .Binder 8.0.0) |
A single imperative read of DelayStart in private DelayStartup(IHost), called from Create after Build() and before Configure. |
Host.CreateDefaultBuilder(args) |
Host |
Microsoft.Extensions.Hosting 8.0.0 |
Registers the default host and app-configuration providers. |
IConfigurationBuilder.AddJsonFile("appsettings.json", optional: true) |
IConfigurationBuilder |
Microsoft.Extensions.Configuration.Json (transitive) |
Appends a second, non-reloading appsettings.json provider after the Generic Host defaults. |
IConfigurationBuilder.AddEnvironmentVariables() |
IConfigurationBuilder |
Microsoft.Extensions.Configuration.EnvironmentVariables (transitive) |
Appends a second, unprefixed environment-variable provider; it is the last provider added, so it has the highest precedence. |
IHostBuilder.UseWindowsService() |
IHostBuilder |
Microsoft.Extensions.Hosting.WindowsServices 8.0.0 |
Enables the Windows Service lifetime; when running under the SCM, also sets the content root to AppContext.BaseDirectory. |
ISaifWindowsServiceLogService.Configure(IEnvironmentClient, IHttpJsonClient) (indirect) |
ServiceProgramRunnerBase.ConfigureLogger (virtual) |
SAIF.NetCore.Services.Contracts |
Resolves IEnvironmentClient and hands it to the logger, which then makes the Environment API reads listed under Transitive configuration. |
appsettings.json and IConfiguration¶
Settings read through IConfiguration (appsettings.json, appsettings.<Environment>.json, environment variables, and any other configured provider).
| Setting key | Required | Default value | Retrieval | Purpose | Consuming class | Source |
|---|---|---|---|---|---|---|
DelayStart |
No | — (absent → no delay) | GetValue<int?> |
Blocks startup for the given number of milliseconds, after the host is built and before the error-handler/logger hooks and IHost.Run(); intended to give a developer time to attach a debugger to an installed service. 0 is no delay; -1 blocks forever (Timeout.Infinite); any other negative value throws ArgumentOutOfRangeException; a non-integer string throws InvalidOperationException. |
ServiceProgramRunnerBase.DelayStartup (private, non-overridable) |
src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceProgramRunnerBase.cs |
DelayStart can be supplied by: an appsettings.json entry, the environment variable DelayStart (highest precedence, because of the re-added provider), or a process command-line argument (--DelayStart=<value>, /DelayStart=<value>, or DelayStart=<value>). For an installed service, the command-line form means the SCM binPath arguments, not the Services console "Start parameters" field — the README documents the wrong mechanism and the wrong key name (DelayStartup), so following it produces no delay*.
Configuration source stack defined by this library. CreateHostBuilder re-appends two providers after the Host.CreateDefaultBuilder defaults (host configuration, appsettings.json, appsettings.{Environment}.json, user secrets in Development, environment variables, command-line args):
| Order | Provider | Added by |
|---|---|---|
| 6 | appsettings.json (optional, reloadOnChange: false) |
ServiceProgramRunnerBase.CreateHostBuilder |
| 7 | Environment variables (unprefixed) | ServiceProgramRunnerBase.CreateHostBuilder |
Resulting precedence (highest first): environment variables > appsettings.json > command line > user secrets > appsettings.{Environment}.json. Consequences: appsettings.{Environment}.json is effectively shadowed for any key also present in appsettings.json; command-line binPath arguments lose to appsettings.json and to environment variables; hot reload of appsettings.json is masked by the non-reloading duplicate provider, since provider 1 reloads but provider 6 (same file) does not.
Code-default tunables (not configuration-bound). ServiceWorker<T>.TaskDelayMilliseconds (default 3000) and ServiceWorker<T>.ShutdownTimeoutSeconds (default 30) are public settable properties with code defaults; consumers may set them from an Environment API value in their own worker constructor, but neither is bound to a configuration key by this library.
Environment variables¶
| Variable | Scope read | Accepted values | Default when unset | Effect | Source |
|---|---|---|---|---|---|
DelayStart |
Process (inherited from machine/service-account environment) | Integer milliseconds | No delay | Startup delay; highest precedence of all DelayStart sources because of the re-added provider. |
src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceProgramRunnerBase.cs |
DOTNET_ENVIRONMENT |
Process | Development, Staging, Production, or any name |
Production |
Selects appsettings.{Environment}.json (largely shadowed, see above) and enables user secrets / DI scope validation in Development. |
Microsoft.Extensions.Hosting CreateDefaultBuilder (framework-standard) |
Any unprefixed Section__Key |
Process | — | — | Overrides the same key from every other source (__ maps to :); applies to every consumer and transitive IConfiguration key, including COREAPIENABLED and AppSettings__ApplicationHost. |
ServiceProgramRunnerBase.CreateHostBuilder (re-added AddEnvironmentVariables()) |
Database connection configuration¶
Not applicable. The library makes no connection reads and resolves no IDBConnectionClient directly. See Transitive configuration for the one connection credential the companion registration can require.
Secure settings¶
Not read directly by this library. For completeness, the companion registration (SAIF.NetCore.ServiceExtensions.RegisterForWindowsService<T>) always calls RegisterDBConnectionClient(), which registers IDBConnectionClient as a lazy singleton factory. That factory — not ConnectionClient itself — performs the secure read the first time a consumer resolves IDBConnectionClient:
| Setting key | Encryption method | Purpose | Consuming class | Source |
|---|---|---|---|---|
dbconnectionclient:connectionservicecreds |
IEnvironmentClient.GetSecureSetting("connectionservicecreds", "dbconnectionclient", hash), where hash comes from a SystemHashService instance the factory constructs directly (new SystemHashService(typeof(ConnectionClient).Assembly), not DI-resolved) and calls .Get(SystemType.WebApp) on (hard-coded SystemType.WebApp, even for Windows Services*) |
Database connection credentials for IDBConnectionClient; the factory splits the returned string on \| and calls ConnectionClient.SetupClientCredentials(credentials[0], credentials[1]) |
RegisterDBConnectionClient (the factory lambda, in SAIF.NetCore.ServiceExtensions) -- ConnectionClient only receives the already-resolved credentials through SetupClientCredentials and does not perform the read itself |
src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cs; src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs |
Transitive configuration (from dependencies)¶
Settings required at runtime by services this library resolves but does not implement. These keys apply when the standard companion registration (SAIF.NetCore.ServiceExtensions.RegisterForWindowsService/RegisterForWindowsService<T>) supplies IWindowsServiceErrorHandler, ISaifWindowsServiceLogService, IEnvironmentClient, and IHttpJsonClient with their shipped implementations; a consumer who registers an equivalent, manually-implemented set of those four contracts instead may read a different set of settings, or none of these, depending on that implementation.
| Setting key | Method | Source dependency | Dependency type | Purpose |
|---|---|---|---|---|
tracingdefaults:loggingapiurl |
IEnvironmentClient.GetSettingValue |
SAIF.NetCore.Logging |
NuGet Package (same-repo) | Logging API base URL, read by SaifWindowsServiceLog.Configure, which this library's ConfigureLogger hook invokes. |
tracingdefaults:logroute |
IEnvironmentClient.GetSettingValue |
SAIF.NetCore.Logging |
NuGet Package (same-repo) | Logging API route, read by the same call. |
{ApplicationName}:logthreshold → fallback tracingdefaults:logthreshold |
IEnvironmentClient.HasSetting/GetSettingValue (read independently in two places: SaifLogBase's own LogThreshold property, and again inside ApiLoggerConfig's constructor for the API-sink-specific level) |
SAIF.NetCore.Logging |
NuGet Package (same-repo) | Minimum log level threshold. |
{ApplicationName}:netcorelogpattern → fallback tracingdefaults:netcorelogpattern |
IEnvironmentClient.HasSetting/GetSettingValue, read inside ApiLoggerConfig's constructor -- ApiLoggerConfig and the base Pattern/Level/LoggerType properties it populates are both declared on SaifLoggerConfig (SaifLoggerConfig.cs), a separate class from the logging-service base SaifLogBase |
SAIF.NetCore.Logging |
NuGet Package (same-repo) | Output template pattern for the API logging sink. |
tracingdefaults:logerrorroute |
— (not read for Windows Services) | SAIF.NetCore.Logging |
NuGet Package (same-repo) | Would be the error-specific logging route; SaifWindowsServiceLog never reads it, so LoggingApiErrorRoute stays null*. |
IEnvironmentClient.TrackName / .ApplicationName |
Client properties | SAIF.NetCore.EnvironmentClient |
NuGet Package (same-repo) | Composes the EventLog source name; an empty TrackName throws on .First()*. |
AppSettings:ApplicationHost |
IConfiguration bootstrap |
SAIF.NetCore.EnvironmentClient |
NuGet Package (same-repo) | Required on developer machines to resolve IEnvironmentClient. |
AppSettings:EnvApiDeveloperOverrideAllowed |
IConfiguration bootstrap |
SAIF.NetCore.EnvironmentClient |
NuGet Package (same-repo) | Optional; default true, set false on non-domain-joined servers. |
AppSettings:EnvApiDeveloperSettingsOverride |
IConfiguration bootstrap |
SAIF.NetCore.EnvironmentClient |
NuGet Package (same-repo) | Optional; developer-only settings override file name. |
EnvironmentClient:GetHostsByTrack:RetryCount |
IConfiguration bootstrap (GetHostsByTrackConfig) |
SAIF.NetCore.EnvironmentClient |
NuGet Package (same-repo) | Optional bootstrap-resilience setting; number of retry attempts for GetHostsByTrack calls (default 3). Not read directly by this library -- it is read only inside IEnvironmentClient's own implementation. |
EnvironmentClient:GetHostsByTrack:RetrySleepMs |
IConfiguration bootstrap (GetHostsByTrackConfig) |
SAIF.NetCore.EnvironmentClient |
NuGet Package (same-repo) | Optional bootstrap-resilience setting; milliseconds to sleep between GetHostsByTrack retries (default 3000). Not read directly by this library. |
COREAPIENABLED |
IConfiguration (unprefixed only; ASPNETCORE_COREAPIENABLED is not mapped in this non-web host*) |
SAIF.NetCore.EnvironmentClient |
NuGet Package (same-repo) | Required for the secure environment client on servers. |
EnvironmentApiUrl |
Environment.GetEnvironmentVariable (bypasses the IConfiguration stack) |
SAIF.NetCore.EnvironmentClient |
NuGet Package (same-repo) | Required; cannot be supplied by appsettings.json or the command line. |
dbconnectionclient:connectionservicecreds |
IEnvironmentClient.GetSecureSetting, secure |
SAIF.NetCore.ServiceExtensions's RegisterDBConnectionClient factory lambda (performs the read itself with a self-constructed SystemHashService, not an injected one) |
NuGet Package (same-repo) | Required only if a consumer resolves IDBConnectionClient. The read and the factory both live in SAIF.NetCore.ServiceExtensions; ConnectionClient (in SAIF.NetCore.DBConnectionClient) only receives the resulting credentials via SetupClientCredentials and does not read the secure setting. On the non-secure RegisterEnvironmentClient() path, this call throws EnvironmentClientException ("Operation not allowed! This application is restricted from retrieving secure settings.") rather than failing with a null hash service. |
Startup ordering note: DelayStart is read before ConfigureLogger resolves IEnvironmentClient, so a configured delay also postpones every transitive read above and the Environment API HTTP calls they trigger — useful when attaching a debugger to step through environment-client bootstrap.
Configuration dependencies¶
| Dependency | Type | Required at | Impact if missing |
|---|---|---|---|
IConfiguration |
service (always registered by the Generic Host) | startup (DelayStartup) |
Not expected to be missing; a null would throw NullReferenceException. |
IWindowsServiceErrorHandler, ISaifWindowsServiceLogService, IEnvironmentClient, IHttpJsonClient |
services (resolved with GetRequiredService) |
startup (Configure/ConfigureLogger) |
InvalidOperationException if any is not registered; the recommended way to supply them is SAIF.NetCore.ServiceExtensions.RegisterForWindowsService/RegisterForWindowsService<T>, though ServiceProgramRunnerBase only requires the four contracts to be resolvable — an equivalent manual registration satisfies the same requirement without that call. |
tracingdefaults:loggingapiurl, tracingdefaults:logroute, non-empty TrackName |
Environment API settings (transitive) | startup (ConfigureLogger) |
Startup fails inside SaifWindowsServiceLog.Configure before the service runs. |
EnvironmentApiUrl |
environment variable (transitive) | startup | IEnvironmentClient resolution fails before ConfigureLogger can run. |
The README documents a debugging technique (/DelayStartup=[ms] as a Services-console start parameter) that does not work: the code reads DelayStart, not DelayStartup, and Windows Service start parameters likely do not reach process Main(string[] args) at all*.
Related documentation¶
- Index
- Overview
- Architecture
- Dependencies
- Operations and processes
- Business rules
- Service registration
- API reference
Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts. Statements marked with ** could not be confirmed; treat as unknown until verified.
Sources¶
src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceProgramRunnerBase.cssrc/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceWorker.cssrc/SAIF.NetCore.WindowsService/README.md(documents the obsolete/DelayStartup=[ms]Services-console parameter and the wrong key name)src/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SaifWindowsServiceLog.cs(logging sink/setting reads triggered byConfigureLogger)src/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SaifLogBase.cs(base-classLogThresholdresolution via its own independentlogthresholdread, and logger-override application; declares the abstractBuildStandardLoggerConfigs/InitializeLoggerInfoLookupsthat populatePatternsfrom eachSaifLoggerConfigsubclass)src/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SaifLoggerConfig.cs(ApiLoggerConfig's constructor is the class that actually reads{ApplicationName}:netcorelogpattern/tracingdefaults:netcorelogpatternand the per-sinklogthresholdfallback;EventLogConfiguses a fixedDefaultPatterninstead and reads no setting)src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/BaseEnvironmentClient.cs,SecureEnvironmentClient.cs(settings resolution behindIEnvironmentClient)src/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/SAIF.NetCore.EnvironmentClient/ClientConfigs/GetHostsByTrackConfig.cs(RetryCount/RetrySleepMsdefaults)src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cs(RegisterDBConnectionClientfactory: constructs its ownSystemHashService, performs the secure credential read, and callsConnectionClient.SetupClientCredentials)src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs(IDBConnectionClientimplementation; receives credentials viaSetupClientCredentialsbut does not itself perform the secure-setting read)