Skip to content

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, enforcing BR-WIN-001 and BR-WIN-002.
  3. Embedded sub-steps from argument resolution: construct an ArgumentResolverBuilder<TArgumentContainer>, call BuildArgumentResolvers (app-specific, no-op by default), auto-register any unconfigured IConvertible property (BR-WIN-007) or flag it as a validation failure (BR-WIN-008), then run each resolver's TryResolveArgument against the parsed argument dictionary.
  4. 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).
  5. RegisterAppDependencies(builder) — delegates to the abstract, app-specific Autofac composition root, then registers CreateApplication as a component factory on the same builder.
  6. The consuming application's RegisterAppDependencies override is expected to call dependency and unit-of-work registration.
  7. using (var container = builder.Build()) — builds the Autofac container for the scope of this run.
  8. var app = container.Resolve<TApplication>() — resolves the concrete application instance (invokes its ConsoleBase constructor, which sets StartTime and calls WriteHeader()).
  9. Resolves IUserProfileService.GetCurrentUser().UserId and IEnvironmentService.GetApplicationTrack() and writes "Running as: {userId} on track: {track}" to the console (WriteCurrentUserAndTrack).
  10. app.Run() — delegates into the console application lifecycle.
  11. Exception handling around steps 6–8:
  12. On a caught SaifConsoleException: writes ex.GetFullFormattedException() to Console.Error and sets Environment.ExitCode = ex.ExitCode (BR-WIN-004).
  13. On any other caught Exception: writes the same formatted output and sets Environment.ExitCode = 5 (BR-WIN-005).
  14. 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.

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).
  • 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.

Sources

  • Console\SAIF.Console\Console\ProgramRunnerBase.cs
  • Console\SAIF.Console\Console\SaifStandardProgramBase.cs