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 subclassSaifStandardProgramBase<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 theInitialize()/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 withArgumentContainerBase<T>→StandardArgumentContainerBase<T>,ArgumentResolverBuilder<T>, andArgumentResolver<T, TArgument>). - Provide a console/file logging subsystem (
IConsoleLogService/ConsoleLogService,ILogWriter/LogWriter) that discovers machine-scopedfile0–file4environment variables and registers one log writer per match. - Provide a data-access composition subsystem (
DatabaseConfig/OracleConfig/SqlServerConfigandAutofacExtensions.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 (
SaifConsoleExceptionand its subclassesBadParameterException,CustomErrorException,DatabaseErrorException,DataErrorException,FileInputOutputException,NoDataFoundException) consumed byProgramRunnerBase.Run()'s catch block to setEnvironment.ExitCode.
Component boundaries¶
- Entry-point/composition layer (
ProgramRunnerBase<TApplication, TArgumentContainer>,SaifStandardProgramBase<TApp, TArgContainer>): owns argument-container construction, argument validation gating, the AutofacContainerBuildercomposition 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 theInitialize()/Execute()/Finish()lifecycle and console header/footer logging via an injectedIConsoleLogService; all concrete behavior is supplied by a consuming subclass. - Argument-parsing subsystem (
ICommandLineParser/PatternCommandLineParser/SaifStandardCommandLineParser,ArgumentContainerBase<T>/StandardArgumentContainerBase<T>,ArgumentResolverBuilder<T>/ArgumentResolver<T, TArgument>, internalIArgumentResolver<T>): parses rawstring[]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 aLogWriterkeyed by a fixedLogTypelookup, in addition to console output. - Data-access composition subsystem (
DatabaseConfig/OracleConfig/SqlServerConfig,AutofacExtensions.RegisterCommonDependencies): registers three namedIUnitOfWorkFactoryinstances ("oracle","oracleStateless","sqlSever") and, per suppliedDatabaseConfig, a namedIUnitOfWork/IRepositoryFactoryregistration 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 (
SaifConsoleExceptionand its typed subclasses): each carries a fixed or caller-suppliedExitCodeconsumed byProgramRunnerBase.Run()'s catch block. - No entity/domain layer: this library defines no NHibernate entity mappings (
ClassMap<T>) itself —dataClassMapAssembliesis a pass-through parameter forwarded toOracleConfigurationFactory/SqlServerConfigurationFactory(both external, fromSAIF.Framework.Data.NHibernate); the consuming application supplies its own mapping assemblies.
Interaction model¶
- A consuming console application's
Main()constructs aProgramRunnerBase/SaifStandardProgramBasesubclass and callsRun(). Run()first buildsArguments = CreateArgumentContainer(RawArguments)(SaifStandardProgramBasesuppliesEnvironment.GetCommandLineArgs()), then callsArguments.ResolveArguments(), which parses raw arguments via the container'sICommandLineParserand binds/validates them through theArgumentResolverBuilder/ArgumentResolverpipeline.- If argument resolution is invalid,
Run()writes errors toConsole.Error, setsEnvironment.ExitCode = 1, blocks onConsole.ReadLine(), and returns without registering dependencies, building the container, or running the application. - If valid,
Run()calls the abstractRegisterAppDependencies(builder)(the consuming application's own Autofac composition-root override, which is expected to callAutofacExtensions.RegisterCommonDependencies), registersCreateApplicationas a component factory, builds the Autofac container, and resolves the concreteTApplication(aConsoleBase<TArgContainer>subclass). Run()resolvesIUserProfileServiceandIEnvironmentServicefrom the container to print the current user and application track, then callsapp.Run(), which executes theConsoleBaseInitialize()/Execute()/Finish()lifecycle (resettingEnvironment.ExitCode = 0after a successfulInitialize()).- Exceptions escaping resolution/
app.Run()are caught: aSaifConsoleExceptionsetsEnvironment.ExitCodefrom its ownExitCodeproperty; any other exception sets a fixed exit code of5.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'sRegisterAppDependenciesoverride calls to register: the three named NHibernate unit-of-work factories, one namedIUnitOfWork/IRepositoryFactoryregistration per suppliedDatabaseConfig, the externalWindowsEnvironmentServiceasIEnvironmentService,ServiceRegistrations.RegisterCoreServicesForWindows, andConsoleLogServiceasIConsoleLogService.- Each
DatabaseConfig.RegisterUnitOfWorkresolvesIEnvironmentServiceat container-build time to compute a connection string (GetConnectionString(env, env.GetConfigSetting(EnvironmentConfigKey))), delegating to the externalDbConnectionManager.GetConnectionStringForInstance(Oracle) orGetConnectionStringForSqlServer(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.
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.
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¶
ProgramRunnerBasenever contains application-specific logic; all application behavior is delegated to the abstractInitialize/Execute/Finishtriplet onConsoleBaseand the abstractCreateApplication/CreateArgumentContainer/RegisterAppDependencies/RawArgumentsmembers 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); on invalid arguments the process halts and requires a console keypress before exiting (BR-WIN-003).
- Exit-code assignment is exception-type-driven: a
SaifConsoleException(or subclass) supplies its ownExitCode; any other unhandled exception is a fixed exit code of5(BR-WIN-004/BR-WIN-005); a successfulInitialize()always resetsEnvironment.ExitCodeto0beforeExecute()runs (BR-WIN-006). - Argument-container properties are either explicitly configured via
BuildArgumentResolvers, auto-resolved via reflection whenIConvertible(BR-WIN-007), or flagged as a validation failure when not convertible and unconfigured (BR-WIN-008) — there is no silent-skip path. AutofacExtensions.RegisterCommonDependenciesis 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 ownRegisterAppDependenciesoverride.AutofacExtensions.RegisterCommonDependenciesunconditionally registersWindowsEnvironmentServiceAs<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.FactoryNameis always the single"sqlSever"factory (name typo preserved verbatim from source), regardless of the inheritedStatelessflag (BR-WIN-015); Oracle'sStatelessflag does select between"oracle"and"oracleStateless"(BR-WIN-016). - 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
EnvironmentConfigKeyare 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¶
Sources¶
Console\SAIF.Console\SAIF.Framework.Windows.csprojConsole\SAIF.Console\Console\ProgramRunnerBase.csConsole\SAIF.Console\Console\SaifStandardProgramBase.csConsole\SAIF.Console\Console\ConsoleBase.csConsole\SAIF.Console\Console\ICommandLineParser.csConsole\SAIF.Console\Console\PatternCommandLineParser.csConsole\SAIF.Console\Console\SaifStandardCommandLineParser.csConsole\SAIF.Console\Console\Arguments\ArgumentContainerBase.csConsole\SAIF.Console\Console\Arguments\ArgumentResolver.csConsole\SAIF.Console\Console\Arguments\ArgumentResolverBuilder.csConsole\SAIF.Console\Console\Arguments\IArgumentResolver.csConsole\SAIF.Console\Console\Arguments\StandardArgumentContainerBase.csConsole\SAIF.Console\Console\ConsoleLogService.csConsole\SAIF.Console\Console\LogWriter.csConsole\SAIF.Console\Console\AutofacExtensions.csConsole\SAIF.Console\Console\DatabaseConfigs\DatabaseConfig.csConsole\SAIF.Console\Console\DatabaseConfigs\OracleConfig.csConsole\SAIF.Console\Console\DatabaseConfigs\SqlServerConfig.csConsole\SAIF.Console\Console\Exceptions\SAIFConsoleException.csConsole\SAIF.Console\Console\Exceptions\BadParameterException.csConsole\SAIF.Console\Console\Exceptions\CustomErrorException.csConsole\SAIF.Console\Console\Exceptions\DatabaseErrorException.csConsole\SAIF.Console\Console\Exceptions\DataErrorException.csConsole\SAIF.Console\Console\Exceptions\FileInputOutputException.csConsole\SAIF.Console\Console\Exceptions\NoDataFoundException.cs