Skip to content

Console application execution lifecycle

This is the template-method lifecycle every console or batch application built on this library follows. clsConsoleBase.Execute() fixes the order of initialization, command-line validation, main-logic execution, and teardown; a batch subclass (clsBatchBase) does not override Execute() itself but overrides Initialize()/Uninitialize() to add multi-stream log registration and a batch header/footer around the same lifecycle.

Field Value
Operation ID OP-CA-001
Trigger Downstream Sub Main instantiates a clsConsoleBase/clsBatchBase subclass and calls Execute()
Inputs Command-line arguments (Environment.GetCommandLineArgs); for a batch subclass, also the set of currently defined environment variables
Outputs ReturnCode / Environment.ExitCode; console output (batch header/footer, prompts); for a batch subclass, flushed/closed log-stream files
Primary components clsConsoleBase.Execute, clsConsoleBase.Initialize, clsConsoleBase.Uninitialize, clsBatchBase.Initialize, clsBatchBase.Uninitialize, clsBatchBase.WriteBatchHeader, clsBatchBase.WriteBatchFooter
Entry point Presentation\SAIF.Presentation.ConsoleApplication\clsConsoleBase.vb

Steps

  1. Construct the application object. The subclass's constructor runs clsConsoleBase.New(), which records m_StartTime = Now for later use by RunningTime/WriteBatchFooter.
  2. Initialize. Execute() calls Initialize().
  3. Base behavior (clsConsoleBase.Initialize): sets ReturnCode = ReturnCodes.UnknownError as the default exit code, then reads Environment.GetCommandLineArgs, and for each argument strips a single leading / or - and upper-cases it before storing it (BR-002).
  4. If the subclass is a clsBatchBase: Initialize() is overridden — it calls MyBase.Initialize() first (running the base behavior above), then scans every current environment variable name and pre-registers any whose upper-cased name matches the pattern FILE? (e.g., FILE0…FILE4) into an internal log-stream table with an empty placeholder value, then calls WriteBatchHeader(), which writes "<AppName> began at <StartTime>" to the console via WriteStatusMsg.
  5. Check for a debug flag. Execute() calls ParamExists("DEBUG") (BR-005); the result is not currently wired to any observable behavior in this library.*
  6. Validate the command line. Execute() calls the abstract ValidateCommandLine(), implemented by the concrete downstream application.
  7. Branch on validation result (BR-003):
  8. If True: Execute() calls the abstract RunAppLogic(), the concrete application's main logic.
  9. If False: Execute() writes "Press enter to continue..." to the console and blocks on Console.Read() instead of calling RunAppLogic().
  10. Uninitialize. Execute() always calls Uninitialize() after the branch above, regardless of which path was taken.
  11. If the subclass is a clsBatchBase: Uninitialize() is overridden — it calls WriteBatchFooter() first, which writes "<AppName> ended at <EndTime>" and "<AppName> ran for <seconds> seconds" to the console; then, for every log-stream entry that was actually opened as a StreamWriter (not left as its empty placeholder string), it flushes and closes that stream; only then does it call MyBase.Uninitialize() (the base implementation is a no-op).
  12. Return. Execute() returns; the process's Environment.ExitCode reflects whatever value was last assigned to ReturnCode (defaulting to UnknownError from step 2 unless RunAppLogic() or another step explicitly sets a different value).*

Process flow

The following diagram visualizes the Execute() template-method lifecycle, including the batch-specific extensions to Initialize()/Uninitialize().

flowchart TD
    Start([Sub Main calls Execute]) --> Init[Initialize:<br>default ReturnCode,<br>parse command line]
    Init --> IsBatch{Batch subclass?}
    IsBatch -->|Yes| BatchInit[Pre-register FILE?<br>environment variables;<br>write batch header]
    IsBatch -->|No| Debug
    BatchInit --> Debug{DEBUG flag present?}
    Debug --> Validate{ValidateCommandLine}
    Validate -->|True| Run[RunAppLogic]
    Validate -->|False| Prompt["Press enter to continue..."]
    Run --> Uninit[Uninitialize]
    Prompt --> Uninit
    Uninit --> IsBatch2{Batch subclass?}
    IsBatch2 -->|Yes| BatchUninit[Write batch footer;<br>flush/close opened log streams]
    IsBatch2 -->|No| End
    BatchUninit --> End([Return; ExitCode reflects ReturnCode])

Failure and edge-case behavior

  • When ValidateCommandLine() returns False, RunAppLogic() is never invoked; the process instead waits indefinitely on Console.Read() for operator input before proceeding to Uninitialize() (BR-003).
  • Uninitialize() always runs after the validate/run branch, so batch log streams are flushed and closed even when RunAppLogic() was never called.
  • ReturnCode defaults to UnknownError at the start of Initialize(); if the concrete RunAppLogic() implementation completes without explicitly setting ReturnCode, the process exits with UnknownError rather than Success.*
  • The /DEBUG check in Execute() calls ParamExists("DEBUG") but the result is not used to alter logging or control flow anywhere in this library's source.*
  • clsBatchBase.Uninitialize only flushes/closes log-stream entries whose stored value is not still the placeholder empty string — a stream that was pre-registered but never actually written to via WriteAppLogMsg is left unopened and is skipped.

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.

Sources

  • Presentation\SAIF.Presentation.ConsoleApplication\clsConsoleBase.vb
  • Presentation\SAIF.Presentation.ConsoleApplication\clsBatchBase.vb