# ASP Classic Framework Reference — RouteKit Classic ASP All new ASP Classic / VB6 web applications in this workspace are built on the **RouteKit Classic ASP MVC framework** (source: `https://onefortheroadgit.sytes.net/dcovington/asp-classic-unified-framework.git`). Do not hand-roll a routing/DAL/error-handling scheme when this framework already provides one — use it, and only extend it inside `app/` (never modify `core/`). ## Directory Layout ``` public/ # IIS site root — Default.asp (front controller), web.config core/ # Framework internals — do not modify autoload_core.asp # loads all core libraries router.wsc # route matching mvc.asp # MVC_Dispatcher_Class — resolves route, validates controller/action against the whitelist, dispatches databaseConnection.asp # DatabaseConnection_Class — ADODB.Connection factory (Access/SQL Server/ODBC) lib.DAL.asp # DAL() singleton — Database_Class initialized from GetAppSetting("ConnectionString") lib.ErrorHandler.asp # ErrorHandler_Class — dev vs prod error display + flat-file logging lib.Migrations.asp # Migrator_Class — schema_migrations table, Up/Down migrations, transactional lib.ControllerRegistry.asp # controller/action name-format + whitelist validation helpers.asp # GetAppSetting(), QuoteValue, FormatDateForSql, etc. app/ controllers/ # one *_Class per controller + autoload_controllers.asp views// # one .asp view per action; app/views/shared/ for header/footer models/ # generated POBOs repositories/ # generated repository classes db/ migrations/ # timestamped *.asp migration files (YYYYMMDDHHMMSS_description.asp) webdata.accdb # the Access database (dev default) scripts/ # code generators, run via cscript tests/ # dev-only aspunit harness — separate IIS app, sibling to public/ ``` ## Adding a Feature (always in this order) 1. `cscript //nologo scripts\generateMigration.vbs create_my_table` → edit the generated `db/migrations/_create_my_table.asp`, implementing `Migration_Up(migration)` / `Migration_Down(migration)` using `MigrationContext_Class` helpers (`CreateTable`, `AddColumn`, `DropColumn`, `CreateIndex`, `ExecuteSQL`). 2. `cscript //nologo scripts\GenerateRepo.vbs /table:my_table /pk:id` → move generated POBO/repository into `app/models/` and `app/repositories/`. 3. `cscript //nologo scripts\generateController.vbs MyController "Index;Show(id);Create;Store"` → move into `app/controllers/`. 4. Wire up: register in `core/lib.ControllerRegistry.asp`, include from `app/controllers/autoload_controllers.asp`, add routes in `public/Default.asp`, add views under `app/views/MyController/`. 5. `cscript //nologo scripts\runMigrations.vbs status` (and `up`) to apply pending migrations — never hand-edit `webdata.accdb`'s schema outside a migration file. ## Database Access - Never open an `ADODB.Connection` directly in a controller/view. Use `DAL()` (`core/lib.DAL.asp`), which wraps `DatabaseConnection()` (`core/databaseConnection.asp`) and is initialized once per request from `GetAppSetting("ConnectionString")` in `public/web.config`. - Connection lifetime is **one HTTP request** — `DAL__Singleton` and `DatabaseConnection__Singleton` are page-scope `Dim` variables, not `Application`-scoped. Never cache a `DAL()`/connection reference in `Session` or `Application` scope; each request must acquire and release its own. - Parameterize all queries; use `QuoteValue()` (`core/helpers.asp`) for any value that must be inlined into dynamic SQL, and `FormatDateForSql()` for date literals. - Schema changes go through `Migrator_Class` (`core/lib.Migrations.asp`) only, run via `scripts/runMigrations.vbs`. `ApplyMigration`/`RollbackMigration` already wrap each migration in `BeginTransaction`/`CommitTransaction`/`RollbackTransaction`. ## Concurrency (multi-session Access writes) This app is a web app where multiple ASP sessions read/write the same `.accdb` concurrently (see `.devfoundry/rules/database-sql.md` for the general rule). In this framework specifically: - Keep connections request-scoped as above — never hold one open across requests, which is what causes most Access lock contention. - Wrap any multi-statement write sequence in a transaction via `DAL()`/`Migrator_Class`-style `BeginTransaction`/`CommitTransaction`/`RollbackTransaction` so partial writes can't leave the `.accdb` in a locked, half-written state. - Run `runMigrations.vbs` (structural changes) during a maintenance window with no concurrent user traffic — the migration's own transaction protects the schema, but table-locking under structural DDL can still starve concurrent user requests. ## Error Handling & Logging - Use `ErrorHandler_Class` (`core/lib.ErrorHandler.asp`) — `ErrorHandler().HandleError(context, Err)` or `ErrorHandler().CheckAndHandle(context)`. It already branches on `GetAppSetting("Environment")` (detailed HTML in `Development`, generic message in `Production`). - Flat-file logging is controlled by `public/web.config` `appSettings`: `EnableErrorLogging` (true/false) and `ErrorLogPath` (absolute path). Set both per environment in `.devfoundry/references/environments.md` once known for this project — do not invent a different logging mechanism. - `core/mvc.asp`'s dispatcher already wraps controller-action execution and calls its own dispatch-error handler; new controllers do not need to duplicate top-level `On Error Resume Next` around the whole action unless doing something the dispatcher doesn't cover. ## Testing (TDD harness) - The framework ships a dev-only `aspunit` harness under `tests/`, run as a **separate IIS application** (sibling to `public/`, parent paths enabled). See `TESTING.md` in the framework repo for full setup. - Test types: `tests/unit/` (deterministic helpers/registry), `tests/component/` (controller/object with controlled setup), `tests/integration/` (router/dispatch, config, rendered-output smoke tests). - A new test page includes `../aspunit/Lib/ASPUnit.asp` and `../bootstrap.asp`, registers a module via `ASPUnit.AddModule(...)`, calls `ASPUnit.Run()`, and must be added to `tests/test-manifest.asp` (manifest is manual, no auto-discovery). - Run via the browser runner (`run-all.asp` inside the `tests/` IIS app) or `tests\run-tests.cmd`. Because a real test harness exists, the TDD rule in `.devfoundry/rules/general.md` applies literally here — write the failing aspunit test first, confirm it fails, then implement. ## Configuration - All project settings live in `public/web.config` `` (`ConnectionString`, `Environment`, `EnableErrorLogging`, `ErrorLogPath`, plus UI/cache settings) and are read via `GetAppSetting(key)` (`core/helpers.asp`), which caches per-key in `Application` scope after first read. - Never hardcode a connection string, log path, or environment flag inside a controller/view/migration — always read it via `GetAppSetting`.