Skip to content

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): if the static ServiceHost is null, call Create(args) (see Create and configure the host) and assign its result to ServiceHost; otherwise reuse the existing host.
  2. 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.
  3. Run the host with ServiceHost.Run() (a framework-standard Microsoft.Extensions.Hosting extension).
  4. This starts every registered IHostedService, so each ServiceWorker<T> begins its loop (see Execute the worker loop), and blocks until shutdown is triggered by the SCM stop, Ctrl+C, or StopAsync from Handle a task error.
  5. On failure: exceptions thrown from StartAsync propagate to Main.

Process flow

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.

Sources

  • src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceProgramRunnerBase.cs