---
title: Program runner entry point
summary: Resolves arguments, composes the Autofac container, resolves the application, runs it, and translates exceptions to a process exit code.
status: draft
owner: <owner>
last_reviewed: 2026-09-15
library: SAIF.Framework.Windows
reference_type: package
operation_id: OP-WIN-001
trigger: Consuming application's Main() calls Run() on a ProgramRunnerBase/SaifStandardProgramBase subclass.
---

# Program runner entry point

`ProgramRunnerBase<TApplication, TArgumentContainer>.Run()` (and its override in `SaifStandardProgramBase<TApp, TArgContainer>`) is the top-level orchestrator a consuming console application calls from `Main()`. It resolves and validates command-line arguments, composes the Autofac container, resolves the concrete application, runs it, and maps any escaping exception to a process exit code.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-WIN-001 |
| **Trigger** | Consuming application's `Main()` constructs a `ProgramRunnerBase`/`SaifStandardProgramBase` subclass and calls `Run()`. |
| **Inputs** | `RawArguments` (abstract property; `SaifStandardProgramBase` supplies `Environment.GetCommandLineArgs()`). |
| **Outputs** | Process `Environment.ExitCode`; console/stderr output. |
| **Primary components** | `ProgramRunnerBase<TApplication, TArgumentContainer>.Run()`, `SaifStandardProgramBase<TApp, TArgContainer>.Run()` |
| **Entry point** | `Console\SAIF.Console\Console\ProgramRunnerBase.cs` |

## Steps

1. `Arguments = CreateArgumentContainer(RawArguments)` — delegates to the abstract, app-specific factory method.
2. `var result = Arguments.ResolveArguments()` — delegates into [argument resolution](resolve-arguments.md), enforcing [BR-WIN-001](../business-rules.md#br-win-001-argument-validation-precedes-application-execution) and [BR-WIN-002](../business-rules.md#br-win-002-unconfigured-argument-properties-must-be-convertible-or-explicitly-configured).
   - Embedded sub-steps from [argument resolution](resolve-arguments.md): construct an `ArgumentResolverBuilder<TArgumentContainer>`, call `BuildArgumentResolvers` (app-specific, no-op by default), auto-register any unconfigured `IConvertible` property ([BR-WIN-007](../business-rules.md#br-win-007-convertible-properties-auto-register)) or flag it as a validation failure ([BR-WIN-008](../business-rules.md#br-win-008-non-convertible-unconfigured-properties-fail-validation)), then run each resolver's `TryResolveArgument` against the parsed argument dictionary.
3. Branch — if `!result.IsValid`: writes all `ValidationFailure` messages to `Console.Error` (via `DisplayErrors`), sets `Environment.ExitCode = 1`, calls `System.Console.ReadLine()` (blocks for a keypress before returning), and returns without registering dependencies, building the container, or running the application ([BR-WIN-003](../business-rules.md#br-win-003-invalid-arguments-halt-before-application-logic)).
4. `RegisterAppDependencies(builder)` — delegates to the abstract, app-specific Autofac composition root, then registers `CreateApplication` as a component factory on the same `builder`.
   - The consuming application's `RegisterAppDependencies` override is expected to call [dependency and unit-of-work registration](register-common-dependencies.md).
5. `using (var container = builder.Build())` — builds the Autofac container for the scope of this run.
6. `var app = container.Resolve<TApplication>()` — resolves the concrete application instance (invokes its `ConsoleBase` constructor, which sets `StartTime` and calls `WriteHeader()`).
7. Resolves `IUserProfileService.GetCurrentUser().UserId` and `IEnvironmentService.GetApplicationTrack()` and writes `"Running as: {userId} on track: {track}"` to the console (`WriteCurrentUserAndTrack`).
8. `app.Run()` — delegates into the [console application lifecycle](console-base-run.md).
9. Exception handling around steps 6–8:
   - On a caught `SaifConsoleException`: writes `ex.GetFullFormattedException()` to `Console.Error` and sets `Environment.ExitCode = ex.ExitCode` ([BR-WIN-004](../business-rules.md#br-win-004-saifconsoleexception-supplies-its-own-exit-code)).
   - On any other caught `Exception`: writes the same formatted output and sets `Environment.ExitCode = 5` ([BR-WIN-005](../business-rules.md#br-win-005-unhandled-exceptions-default-to-exit-code-5)).
10. `SaifStandardProgramBase.Run()` (override) calls `base.Run()` then always prints `"Exit Code: " + Environment.ExitCode` to the console, regardless of outcome.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([Main calls Run]) --> CreateArgs[CreateArgumentContainer]
	CreateArgs --> Resolve[Arguments.ResolveArguments]
	Resolve --> Valid{IsValid?}
	Valid -->|No| Halt([ExitCode=1, Console.Error, ReadLine block])
	Valid -->|Yes| Register[RegisterAppDependencies + Build container]
	Register --> ResolveApp[Resolve TApplication]
	ResolveApp --> Banner[Write current user and track]
	Banner --> AppRun[app.Run]
	AppRun --> Outcome{Exception?}
	Outcome -->|SaifConsoleException| ExitEx([ExitCode = ex.ExitCode])
	Outcome -->|Other| Exit5([ExitCode = 5])
	Outcome -->|No| Exit0([ExitCode unchanged / 0])
```

## Failure and edge-case behavior
- Invalid arguments prevent any dependency registration, container build, or application resolution; the process blocks on a console keypress before returning ([BR-WIN-003](../business-rules.md#br-win-003-invalid-arguments-halt-before-application-logic)).
- A `SaifConsoleException` subclass's own `ExitCode` is always honored over the generic fallback of `5`.
- `SaifStandardProgramBase.Run()` always prints the final exit code, even on the success path.

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

## Sources
- `Console\SAIF.Console\Console\ProgramRunnerBase.cs`
- `Console\SAIF.Console\Console\SaifStandardProgramBase.cs`
