---
title: SAIF.Framework.Windows architecture
summary: Architectural responsibilities, boundaries, and interaction patterns.
status: draft
owner: <owner>
last_reviewed: 2026-09-15
library: SAIF.Framework.Windows
reference_type: package
---

# SAIF.Framework.Windows architecture

`SAIF.Framework.Windows` (packaged as `SAIF.Framework.Windows`, assembly `SAIF.Framework.Console`, root namespace `SAIF.Console`) is a Framework4-classified, generic console/batch-application composition framework: it supplies the entry-point orchestration, command-line argument parsing/validation, console logging, and Autofac-based NHibernate unit-of-work DI wiring that a consuming console application builds on top of, but it defines no concrete application, entity mappings, or authorization logic of its own.

## Responsibilities
- Provide an entry-point orchestrator (`ProgramRunnerBase<TApplication, TArgumentContainer>` and its standardized subclass `SaifStandardProgramBase<TApp, TArgContainer>`) that resolves command-line arguments, builds the Autofac composition root, resolves the concrete application, and translates exceptions to process exit codes.
- Provide an application lifecycle base (`ConsoleBase<TArgContainer>`) that owns the `Initialize()`/`Execute()`/`Finish()` lifecycle, run timing (`StartTime`/`EndTime`/`RunningTime`), and console header/footer output.
- Provide a reflection-driven command-line argument parsing and validation subsystem (`ICommandLineParser` → `PatternCommandLineParser` → `SaifStandardCommandLineParser`, paired with `ArgumentContainerBase<T>` → `StandardArgumentContainerBase<T>`, `ArgumentResolverBuilder<T>`, and `ArgumentResolver<T, TArgument>`).
- Provide a console/file logging subsystem (`IConsoleLogService`/`ConsoleLogService`, `ILogWriter`/`LogWriter`) that discovers machine-scoped `file0`–`file4` environment variables and registers one log writer per match.
- Provide a data-access composition subsystem (`DatabaseConfig`/`OracleConfig`/`SqlServerConfig` and `AutofacExtensions.RegisterCommonDependencies`) that registers named NHibernate unit-of-work factories (Oracle stateful, Oracle stateless, SQL Server) and per-instance unit-of-work registrations into the consuming application's Autofac container.
- Provide a typed exception/exit-code hierarchy (`SaifConsoleException` and its subclasses `BadParameterException`, `CustomErrorException`, `DatabaseErrorException`, `DataErrorException`, `FileInputOutputException`, `NoDataFoundException`) consumed by `ProgramRunnerBase.Run()`'s catch block to set `Environment.ExitCode`.

## Component boundaries
- **Entry-point/composition layer** (`ProgramRunnerBase<TApplication, TArgumentContainer>`, `SaifStandardProgramBase<TApp, TArgContainer>`): owns argument-container construction, argument validation gating, the Autofac `ContainerBuilder` composition root, application resolution, and top-level exception-to-exit-code translation. Never touches application-specific logic — that is delegated to abstract members (`CreateApplication`, `CreateArgumentContainer`, `RegisterAppDependencies`, `RawArguments`).
- **Application layer** (`ConsoleBase<TArgContainer>`): owns the `Initialize()`/`Execute()`/`Finish()` lifecycle and console header/footer logging via an injected `IConsoleLogService`; all concrete behavior is supplied by a consuming subclass.
- **Argument-parsing subsystem** (`ICommandLineParser`/`PatternCommandLineParser`/`SaifStandardCommandLineParser`, `ArgumentContainerBase<T>`/`StandardArgumentContainerBase<T>`, `ArgumentResolverBuilder<T>`/`ArgumentResolver<T, TArgument>`, internal `IArgumentResolver<T>`): parses raw `string[]` arguments into a dictionary, then binds/validates them onto a consuming application's argument container via explicit or reflection-driven resolvers.
- **Logging subsystem** (`IConsoleLogService`/`ConsoleLogService`, `ILogWriter`/`LogWriter`): discovers machine-level environment variables matching `^file[0-4]` and wraps each in a `LogWriter` keyed by a fixed `LogType` lookup, in addition to console output.
- **Data-access composition subsystem** (`DatabaseConfig`/`OracleConfig`/`SqlServerConfig`, `AutofacExtensions.RegisterCommonDependencies`): registers three named `IUnitOfWorkFactory` instances (`"oracle"`, `"oracleStateless"`, `"sqlSever"`) and, per supplied `DatabaseConfig`, a named `IUnitOfWork`/`IRepositoryFactory` registration into the same Autofac container used by the entry-point layer. This is the single integration point where the DI/composition layer, the data-access subsystem, and core framework services (`IEnvironmentService`, `IConsoleLogService`) are wired together.
- **Exception/exit-code subsystem** (`SaifConsoleException` and its typed subclasses): each carries a fixed or caller-supplied `ExitCode` consumed by `ProgramRunnerBase.Run()`'s catch block.
- **No entity/domain layer**: this library defines no NHibernate entity mappings (`ClassMap<T>`) itself — `dataClassMapAssemblies` is a pass-through parameter forwarded to `OracleConfigurationFactory`/`SqlServerConfigurationFactory` (both external, from `SAIF.Framework.Data.NHibernate`); the consuming application supplies its own mapping assemblies.

## Interaction model
- A consuming console application's `Main()` constructs a `ProgramRunnerBase`/`SaifStandardProgramBase` subclass and calls `Run()`.
- `Run()` first builds `Arguments = CreateArgumentContainer(RawArguments)` (`SaifStandardProgramBase` supplies `Environment.GetCommandLineArgs()`), then calls `Arguments.ResolveArguments()`, which parses raw arguments via the container's `ICommandLineParser` and binds/validates them through the `ArgumentResolverBuilder`/`ArgumentResolver` pipeline.
- If argument resolution is invalid, `Run()` writes errors to `Console.Error`, sets `Environment.ExitCode = 1`, blocks on `Console.ReadLine()`, and returns without registering dependencies, building the container, or running the application.
- If valid, `Run()` calls the abstract `RegisterAppDependencies(builder)` (the consuming application's own Autofac composition-root override, which is expected to call `AutofacExtensions.RegisterCommonDependencies`), registers `CreateApplication` as a component factory, builds the Autofac container, and resolves the concrete `TApplication` (a `ConsoleBase<TArgContainer>` subclass).
- `Run()` resolves `IUserProfileService` and `IEnvironmentService` from the container to print the current user and application track, then calls `app.Run()`, which executes the `ConsoleBase` `Initialize()`/`Execute()`/`Finish()` lifecycle (resetting `Environment.ExitCode = 0` after a successful `Initialize()`).
- Exceptions escaping resolution/`app.Run()` are caught: a `SaifConsoleException` sets `Environment.ExitCode` from its own `ExitCode` property; any other exception sets a fixed exit code of `5`. `SaifStandardProgramBase.Run()` additionally always prints the final exit code.
- `AutofacExtensions.RegisterCommonDependencies(builder, currentUserId, dataClassMapAssemblies, params DatabaseConfig[] configs)` is the composition entry point a consuming application's `RegisterAppDependencies` override calls to register: the three named NHibernate unit-of-work factories, one named `IUnitOfWork`/`IRepositoryFactory` registration per supplied `DatabaseConfig`, the external `WindowsEnvironmentService` as `IEnvironmentService`, `ServiceRegistrations.RegisterCoreServicesForWindows`, and `ConsoleLogService` as `IConsoleLogService`.
- Each `DatabaseConfig.RegisterUnitOfWork` resolves `IEnvironmentService` at container-build time to compute a connection string (`GetConnectionString(env, env.GetConfigSetting(EnvironmentConfigKey))`), delegating to the external `DbConnectionManager.GetConnectionStringForInstance` (Oracle) or `GetConnectionStringForSqlServer` (SQL Server).

## Architecture diagram
The following diagram shows how a consuming console application composes with this framework's entry-point, argument, logging, and data-access-composition subsystems.

```mermaid
flowchart TD
	App[Consuming console application<br>Main] --> SPB[SaifStandardProgramBase /<br>ProgramRunnerBase]
	SPB --> ACB[ArgumentContainerBase /<br>StandardArgumentContainerBase]
	ACB --> CLP[ICommandLineParser<br>PatternCommandLineParser /<br>SaifStandardCommandLineParser]
	ACB --> ARB[ArgumentResolverBuilder /<br>ArgumentResolver]
	SPB --> AFX[AutofacExtensions.<br>RegisterCommonDependencies]
	AFX --> DBC[DatabaseConfig<br>OracleConfig / SqlServerConfig]
	DBC --> UOW[NHibernate unit-of-work factories<br>oracle / oracleStateless / sqlSever]
	AFX --> ENV[WindowsEnvironmentService<br>As IEnvironmentService]
	AFX --> CLS[ConsoleLogService<br>As IConsoleLogService]
	SPB --> CB[ConsoleBase<br>Initialize / Execute / Finish]
	CB --> CLS
	CLS --> LW[LogWriter instances<br>file0-file4 / Custom]
	SPB --> EXC[SaifConsoleException hierarchy<br>maps to Environment.ExitCode]
```

## Sequence diagram
The following diagram shows the primary `Run()` request/response sequence from process start to exit-code assignment.

```mermaid
sequenceDiagram
	participant Main as Consuming app Main
	participant PRB as ProgramRunnerBase.Run
	participant ACB as ArgumentContainerBase
	participant Container as Autofac container
	participant App as ConsoleBase.Run
	Main->>PRB: Run()
	PRB->>ACB: CreateArgumentContainer + ResolveArguments()
	ACB-->>PRB: ValidationResult
	alt invalid arguments
		PRB-->>Main: ExitCode=1, Console.Error, ReadLine block
	else valid arguments
		PRB->>Container: RegisterAppDependencies + Build()
		Container-->>PRB: TApplication instance
		PRB->>App: app.Run()
		App-->>PRB: Initialize/Execute/Finish complete
		PRB-->>Main: ExitCode from SaifConsoleException or 0/5
	end
```

## Design constraints
- `ProgramRunnerBase` never contains application-specific logic; all application behavior is delegated to the abstract `Initialize`/`Execute`/`Finish` triplet on `ConsoleBase` and the abstract `CreateApplication`/`CreateArgumentContainer`/`RegisterAppDependencies`/`RawArguments` members on itself — this library defines only generic scaffolding.
- Argument validation always runs before any application dependency registration, container build, or application resolution ([BR-WIN-001](business-rules.md#br-win-001-argument-validation-precedes-application-execution)); on invalid arguments the process halts and requires a console keypress before exiting ([BR-WIN-003](business-rules.md#br-win-003-invalid-arguments-halt-before-application-logic)).
- Exit-code assignment is exception-type-driven: a `SaifConsoleException` (or subclass) supplies its own `ExitCode`; any other unhandled exception is a fixed exit code of `5` ([BR-WIN-004](business-rules.md#br-win-004-saifconsoleexception-supplies-its-own-exit-code)/[BR-WIN-005](business-rules.md#br-win-005-unhandled-exceptions-default-to-exit-code-5)); a successful `Initialize()` always resets `Environment.ExitCode` to `0` before `Execute()` runs ([BR-WIN-006](business-rules.md#br-win-006-successful-initialize-resets-exit-code)).
- Argument-container properties are either explicitly configured via `BuildArgumentResolvers`, auto-resolved via reflection when `IConvertible` ([BR-WIN-007](business-rules.md#br-win-007-convertible-properties-auto-register)), or flagged as a validation failure when not convertible and unconfigured ([BR-WIN-008](business-rules.md#br-win-008-non-convertible-unconfigured-properties-fail-validation)) — there is no silent-skip path.
- `AutofacExtensions.RegisterCommonDependencies` is the single integration point wiring the DI/composition layer, the data-access subsystem, and core framework services together; a consuming application must call it from its own `RegisterAppDependencies` override.
- `AutofacExtensions.RegisterCommonDependencies` unconditionally registers `WindowsEnvironmentService` `As<IEnvironmentService>()` — the concrete environment-service implementation is fixed by this framework, not independently configurable per consuming application short of re-registration.
- SQL Server unit-of-work registration has no stateless-session variant: `SqlServerConfig.FactoryName` is always the single `"sqlSever"` factory (name typo preserved verbatim from source), regardless of the inherited `Stateless` flag ([BR-WIN-015](business-rules.md#br-win-015-sql-server-has-no-stateless-factory-variant)); Oracle's `Stateless` flag does select between `"oracle"` and `"oracleStateless"` ([BR-WIN-016](business-rules.md#br-win-016-oracle-factory-selection-driven-by-stateless-flag)).
- This library defines no NHibernate entity mappings and performs no credential retrieval of its own; mapping assemblies, connection instance/user/server names, and the meaning of `EnvironmentConfigKey` are all supplied by the consuming application.
- No authentication/authorization patterns exist in this library; any such concerns are the responsibility of a consuming application's own composition root and business logic.

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Operations and processes](operations-processes.md)
- [Business rules](business-rules.md)
- [API reference](api/index.md)

## Sources
- `Console\SAIF.Console\SAIF.Framework.Windows.csproj`
- `Console\SAIF.Console\Console\ProgramRunnerBase.cs`
- `Console\SAIF.Console\Console\SaifStandardProgramBase.cs`
- `Console\SAIF.Console\Console\ConsoleBase.cs`
- `Console\SAIF.Console\Console\ICommandLineParser.cs`
- `Console\SAIF.Console\Console\PatternCommandLineParser.cs`
- `Console\SAIF.Console\Console\SaifStandardCommandLineParser.cs`
- `Console\SAIF.Console\Console\Arguments\ArgumentContainerBase.cs`
- `Console\SAIF.Console\Console\Arguments\ArgumentResolver.cs`
- `Console\SAIF.Console\Console\Arguments\ArgumentResolverBuilder.cs`
- `Console\SAIF.Console\Console\Arguments\IArgumentResolver.cs`
- `Console\SAIF.Console\Console\Arguments\StandardArgumentContainerBase.cs`
- `Console\SAIF.Console\Console\ConsoleLogService.cs`
- `Console\SAIF.Console\Console\LogWriter.cs`
- `Console\SAIF.Console\Console\AutofacExtensions.cs`
- `Console\SAIF.Console\Console\DatabaseConfigs\DatabaseConfig.cs`
- `Console\SAIF.Console\Console\DatabaseConfigs\OracleConfig.cs`
- `Console\SAIF.Console\Console\DatabaseConfigs\SqlServerConfig.cs`
- `Console\SAIF.Console\Console\Exceptions\SAIFConsoleException.cs`
- `Console\SAIF.Console\Console\Exceptions\BadParameterException.cs`
- `Console\SAIF.Console\Console\Exceptions\CustomErrorException.cs`
- `Console\SAIF.Console\Console\Exceptions\DatabaseErrorException.cs`
- `Console\SAIF.Console\Console\Exceptions\DataErrorException.cs`
- `Console\SAIF.Console\Console\Exceptions\FileInputOutputException.cs`
- `Console\SAIF.Console\Console\Exceptions\NoDataFoundException.cs`
