---
title: Run the Windows Service program
summary: Builds the host once (if needed) and runs it, blocking until shutdown.
status: draft
owner: SAIF Framework Platform Team
last_reviewed: 2026-10-02
library: SAIF.NetCore.WindowsService
reference_type: package
operation_id: OP-01
trigger: The consumer's static void Main(string[] args) calls new Program().Run(args)
---

# Run the Windows Service program

| Field | Value |
| --- | --- |
| **Operation ID** | OP-01 |
| **Trigger** | The consumer's `static void Main(string[] args)` calls `new Program().Run(args)` |
| **Inputs** | Command-line `args` (forwarded to `Host.CreateDefaultBuilder`) |
| **Outputs** | Blocks until the host shuts down; side effect of setting the static `ServiceHost` |
| **Primary components** | `ServiceProgramRunnerBase.Run` |
| **Entry point** | `src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceProgramRunnerBase.cs` |

## Steps

1. Build the host only once ([WS-BR-01](../business-rules.md#ws-br-01-host-is-created-once-per-process)): if the static `ServiceHost` is `null`, call `Create(args)` (see [Create and configure the host](op-02-create-host.md)) and assign its result to `ServiceHost`; otherwise reuse the existing host.
   - Branch: if `ServiceHost` was set earlier (for example by a test, or an earlier `Create` call), `Create` -- and therefore the startup delay and the `Configure` hooks -- is skipped entirely.
2. Run the host with `ServiceHost.Run()` (a framework-standard `Microsoft.Extensions.Hosting` extension).
   - This starts every registered `IHostedService`, so each `ServiceWorker<T>` begins its loop (see [Execute the worker loop](op-05-execute-worker-loop.md)), and blocks until shutdown is triggered by the SCM stop, Ctrl+C, or `StopAsync` from [Handle a task error](op-07-handle-task-error.md).
   - On failure: exceptions thrown from `StartAsync` propagate to `Main`.

## Process flow

```mermaid
flowchart TD
	Start([Main calls Run args]) --> Check{ServiceHost == null?}
	Check -->|Yes| CreateCall[Create args]
	Check -->|No| RunHost
	CreateCall --> Assign[Assign result to ServiceHost]
	Assign --> RunHost[ServiceHost.Run - blocks]
	RunHost --> Shutdown(["Host shuts down, Run returns"])
```

## Failure and edge-case behavior
- A `ServiceHost` pre-set before `Run` is called skips `Create` entirely, including the startup delay and the error-handler/logger configuration hooks.
- Any exception thrown while starting a hosted service (`StartAsync`) propagates out of `Run` to `Main`.

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

## Sources
- `src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceProgramRunnerBase.cs`
