---
title: Create and configure the host
summary: Builds the host, applies the optional startup delay, and runs the error-handler/logger configuration hooks.
status: draft
owner: SAIF Framework Platform Team
last_reviewed: 2026-10-02
library: SAIF.NetCore.WindowsService
reference_type: package
operation_id: OP-02
trigger: OP-01 step 1, or a direct consumer call to Create
---

# Create and configure the host

| Field | Value |
| --- | --- |
| **Operation ID** | OP-02 |
| **Trigger** | [Run the Windows Service program](op-01-run-program.md) 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](op-03-create-host-builder.md), overridable), then `.Build()` it and assign the result to `ServiceHost`.
   - The consumer override normally chains `.ConfigureServices` with a lambda to call `RegisterForWindowsService()` and `AddHostedService<TWorker>()`.
   - On failure: DI validation errors (when `ValidateOnBuild` is enabled in the Development environment) surface here.
2. Delay startup when configured ([WS-BR-02](../business-rules.md#ws-br-02-optional-startup-delay-blocks-before-hooks-and-run)): call `DelayStartup(ServiceHost)`, which resolves `IConfiguration` with `GetService`, reads `GetValue<int?>("DelayStart")`, and calls `Thread.Sleep(value)` if a value is present.
   - 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.
3. Run the configuration hooks with `Configure(ServiceHost)` ([WS-BR-04](../business-rules.md#ws-br-04-error-handler-hook-runs-before-the-logger-is-configured)), in order:
   1. 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](../business-rules.md#ws-br-05-required-hosting-services-must-be-registered)).
   2. Configure the logger with `ConfigureLogger(host)` ([WS-BR-05](../business-rules.md#ws-br-05-required-hosting-services-must-be-registered)): 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/operations/op-02-configure-windows-service-logger.md) (`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`.
4. Return `ServiceHost`.

## Process flow

```mermaid
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.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

> **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`)
