Skip to content

Create and configure the host

Field Value
Operation ID OP-02
Trigger Run the Windows Service program step 1, or a direct consumer call
Inputs args
Outputs A built, configured IHost, also stored in static ServiceHost
Primary components ServiceProgramRunnerBase.Create, DelayStartup (private), Configure, ConfigureLogger
Entry point src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceProgramRunnerBase.cs

Steps

  1. Build the host builder with CreateHostBuilder(args) (see Create the default host builder, overridable), then .Build() it and assign the result to ServiceHost.
  2. The consumer override normally chains .ConfigureServices with a lambda to call RegisterForWindowsService() and AddHostedService<TWorker>().
  3. On failure: DI validation errors (when ValidateOnBuild is enabled in the Development environment) surface here.
  4. Delay startup when configured (WS-BR-02): call DelayStartup(ServiceHost), which resolves IConfiguration with GetService, reads GetValue<int?>("DelayStart"), and calls Thread.Sleep(value) if a value is present.
  5. On failure: a non-integer value throws InvalidOperationException from the binder. A negative value other than -1 throws ArgumentOutOfRangeException; -1 sleeps forever (Thread.Sleep(Timeout.Infinite))*. If IConfiguration were unregistered, this would throw NullReferenceException -- but the Generic Host always registers it.
  6. Run the configuration hooks with Configure(ServiceHost) (WS-BR-04), in order:
  7. Resolve IWindowsServiceErrorHandler with GetRequiredService and pass it to ConfigureErrorHandler (empty by default; consumers override it to add shutdown-exempt types and special actions).
    • On failure: InvalidOperationException if the handler is not registered (WS-BR-05).
  8. Configure the logger with ConfigureLogger(host) (WS-BR-05): resolve ISaifWindowsServiceLogService, IEnvironmentClient, and IHttpJsonClient with GetRequiredService, then call logger.Configure(envClient, httpClient).
    • Delegates to SAIF.NetCore.Logging's SaifWindowsServiceLog.Configure(IEnvironmentClient, IHttpJsonClient): builds the standard logger configuration, reads tracingdefaults:loggingapiurl and tracingdefaults:logroute through IEnvironmentClient.GetSettingValue (tracingdefaults:logerrorroute is not read for Windows Services, so the API error route stays null), computes the EventLog source name from TrackName/ApplicationName, and replaces the process-global Serilog logger with EventLog, Logging API, and Console sinks. > Origin: This delegation is implemented in OP-02: Configure the Windows Service logger (SaifWindowsServiceLog) (SAIF.NetCore.Logging) and executed on behalf of this operation.
    • On failure: an exception in ConfigureErrorHandler aborts Create before the logger is configured, so that failure is never written to EventLog or the Logging API; it propagates out of Run to Main.
  9. Return ServiceHost.

Process flow

flowchart TD
    Start([Create args]) --> Build[CreateHostBuilder then Build]
    Build --> Assign[Assign to ServiceHost]
    Assign --> DelayCheck{DelayStart configured?}
    DelayCheck -->|Yes| Sleep[Thread.Sleep DelayStart]
    DelayCheck -->|No| Hooks
    Sleep --> Hooks["Configure: ConfigureErrorHandler"]
    Hooks --> Logger["ConfigureLogger: resolve env/http, call logger.Configure"]
    Logger --> Return([Return ServiceHost])

Failure and edge-case behavior

  • A non-integer DelayStart value throws InvalidOperationException; construction of the host aborts.
  • DelayStart = -1 blocks the main thread forever*.
  • Missing IWindowsServiceErrorHandler/ISaifWindowsServiceLogService/IEnvironmentClient/IHttpJsonClient registrations throw InvalidOperationException from GetRequiredService.
  • An exception thrown inside the consumer's ConfigureErrorHandler override skips logger configuration and propagates to Main, so the failure is never logged through the SAIF logger.

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.cs
  • src/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SAIF.NetCore.Logging/SaifWindowsServiceLog.cs (logger sink configuration and the tracingdefaults:* reads performed by Configure)