|
|
|
@@ -0,0 +1,152 @@ |
|
|
|
# WSC-MVC — Technical and Product Specification |
|
|
|
|
|
|
|
Version: 0.1 (development specification) |
|
|
|
Status: Proposed; implementation behavior must be verified on the target Windows/IIS host. |
|
|
|
|
|
|
|
## 1. Mission |
|
|
|
Build a small, maintainable, WSC-first MVC framework for Classic ASP. IIS receives HTTP traffic; a single ASP bootstrap dispatches requests to VBScript Windows Script Components registered as COM objects. Application behavior lives in WSC files; presentation lives in separate HTML templates. Ship verified increments rather than an elaborate untested framework. |
|
|
|
|
|
|
|
## 2. Fixed decisions |
|
|
|
- Runtime: Windows, IIS, Classic ASP, VBScript; no ASP.NET, PHP, Node.js, or JScript runtime dependency. |
|
|
|
- Object architecture: registered `.wsc` COM components; stable ProgIDs and CLSIDs. |
|
|
|
- Presentation: separate `.html` templates, served only through the rendering layer when containing placeholders or private content. |
|
|
|
- Entry point: one `Default.asp`, plus IIS rewrite configuration and optional `Global.asa` only if justified. |
|
|
|
- IIS is a hard runtime requirement for HTTP integration; WSH-based component smoke tests are a separate concern. |
|
|
|
- Prefer built-in Windows/IIS capabilities and ADODB; no third-party framework required. |
|
|
|
- Business logic must not reference ASP Request, Response, Server, or Session. |
|
|
|
- All behavior dependent on WSC/COM/IIS quirks must be tested on Windows and documented; do not infer support from ordinary VBScript class behavior. |
|
|
|
|
|
|
|
## 3. Non-goals for v0.1 |
|
|
|
No ORM, controller auto-discovery, automatic reflection, hot reload, plugin system, migrations, authentication, session-backed COM instances, application-scoped WSC instances, database-backed example, complex DI, or production-ready HTML parser. Do not implement these speculatively. |
|
|
|
|
|
|
|
## 4. Initial execution path |
|
|
|
`GET /hello` -> IIS URL Rewrite -> `/Default.asp` -> `Server.CreateObject("WscMvc.Application")` -> `Application.Run(...)` -> `WscMvc.HomeController` -> string/response contract -> HTTP 200, `text/html; charset=utf-8`, body `Hello from WSC-MVC!`. |
|
|
|
|
|
|
|
Prefer a bootstrap with `Option Explicit`, no business logic, no includes, no embedded HTML, and only request-host wiring. Define and verify a precise ownership rule for HTTP status, headers, and writing: do not write a partially successful response before dispatch can fail. Test whether COM calls can accept the proposed ASP built-in objects; if passing an object fails, use a tested host adapter or pass only primitive request data. Do not silently assume an ASP object is serializable or universally callable from WSC. |
|
|
|
|
|
|
|
## 5. Target project structure |
|
|
|
``` |
|
|
|
WSC-MVC/ |
|
|
|
Default.asp |
|
|
|
web.config |
|
|
|
Framework/ |
|
|
|
Application.wsc |
|
|
|
Router.wsc # phase 3 |
|
|
|
RequestContext.wsc # phase 2; only after host interop proven |
|
|
|
ResponseResult.wsc # phase 2; optional if simpler contract works |
|
|
|
ViewRenderer.wsc # phase 4 |
|
|
|
Controllers/ |
|
|
|
HomeController.wsc |
|
|
|
Views/ |
|
|
|
Home.html # phase 4 |
|
|
|
Layout.html # phase 4 |
|
|
|
tests/ |
|
|
|
Test-Components.vbs |
|
|
|
Test-Http.ps1 |
|
|
|
tools/ |
|
|
|
Register-Components.ps1 |
|
|
|
Unregister-Components.ps1 |
|
|
|
docs/ |
|
|
|
ARCHITECTURE.md |
|
|
|
DECISIONS.md |
|
|
|
TEST-RESULTS.md |
|
|
|
SPEC.md |
|
|
|
IMPLEMENTATION_PLAN.md |
|
|
|
AGENTS.md |
|
|
|
CLAUDE.md |
|
|
|
README.md |
|
|
|
``` |
|
|
|
The tree is a target, not an instruction to create placeholder classes before their phase. |
|
|
|
|
|
|
|
## 6. Component contract |
|
|
|
- Each `.wsc` represents one named, cohesive component. The `.wsc` XML `<registration>` establishes COM identity; `<public>` explicitly lists callable methods/properties; `<script language="VBScript">` contains implementation. |
|
|
|
- Do not assume a VBScript `Class ... End Class` placed inside a WSC becomes its exposed COM object. Use and validate the WSC script/public syntax on the target host. |
|
|
|
- Use PascalCase for file names and public members, `WscMvc.ComponentName` ProgIDs, and a unique, stable GUID per component (never recycle across unrelated components). |
|
|
|
- A component has a minimal documented public API. Unexposed functions remain internal. `Initialize(...)` is a framework convention, not an automatic WSC constructor. |
|
|
|
- Use explicit parameter and return contracts, including whether values are objects (`Set`) or scalars, and how missing/Null/Empty values are handled. |
|
|
|
- Use composition; do not invent inheritance, decorators, interfaces, or reflection that VBScript/WSC cannot provide. |
|
|
|
- Limit cross-component COM calls inside hot loops; keep interface calls coarse enough to measure. |
|
|
|
- Do not store ASP host objects or mutable request data in persistent scopes. |
|
|
|
|
|
|
|
## 7. HTTP and routing contract (phase 3) |
|
|
|
- Support GET and POST initially; distinguish unsupported methods with a deliberate HTTP status. |
|
|
|
- Normalize path consistently; preserve an explicit original path; match literal routes before parameterized routes. |
|
|
|
- URL-decode exactly once where appropriate; validate route values and reject ambiguous or malformed paths rather than guessing. |
|
|
|
- Static assets bypass the rewrite. WSC, config, source, tests, logs, and private templates must not be served publicly. |
|
|
|
- Return deliberate 404 for unmatched routes, 405 for disallowed methods (with Allow where possible), 400 for malformed requests, 500 for unexpected failures. |
|
|
|
- Don't use unvalidated request values as filesystem paths, ProgIDs, method names, SQL identifiers, or template names. |
|
|
|
- Do not implement arbitrary controller/method activation from a URL; use an explicit allowlisted route map. |
|
|
|
|
|
|
|
## 8. View contract (phase 4) |
|
|
|
- Templates live separately from code and are not directly browser-accessible if they contain private information or placeholders. |
|
|
|
- Default-encode data for HTML text; define separate, explicit handling for attributes, URLs, JS contexts, and raw HTML. Avoid unsafe universal substitution. |
|
|
|
- Never execute VBScript or arbitrary expression code supplied by a template. Prefer a minimal documented placeholder syntax. |
|
|
|
- Use a deliberate layout convention and report missing templates as server errors without exposing local filesystem paths. |
|
|
|
|
|
|
|
## 9. Database contract (later phase) |
|
|
|
- ADODB with provider-specific adapters only when needed; parameterized commands for values, never string-concatenate untrusted SQL data. |
|
|
|
- Parameterize with correct order/type/size for the provider; identifier selection must use an allowlist. |
|
|
|
- Connection, recordset, command, and transaction ownership must be explicit. Release objects and close resources on success and failure. |
|
|
|
- Services/repositories do not depend on ASP host objects. Transactions have a clear owner and rollback path. |
|
|
|
|
|
|
|
## 10. Security and operations |
|
|
|
- Default deny direct HTTP access to `.wsc`, `.vbs`, `.ps1`, `.md`, `.config` where appropriate, source/private directories, test output, logs, and templates. IIS configuration must be tested, including direct-extension and path variations. |
|
|
|
- Avoid printing debug stacks, COM registration details, connection strings, paths, secrets, or raw exception text to clients. |
|
|
|
- Record request correlation ID, route, elapsed time, outcome, and safe diagnostic information without sensitive payloads. |
|
|
|
- No broad filesystem write privileges. Register WSCs from an elevated, controlled deployment step; do not let a web request register COM classes. |
|
|
|
- Validate application pool identity, architecture (32/64-bit), DCOM/COM permissions where applicable, and IIS/ASP feature installation. |
|
|
|
- Do not cache COM objects in Session/Application. Favor short-lived request-owned instances and document threading implications. |
|
|
|
- Changes to COM registration must be idempotent, reversible, and explicit about privilege and architecture. |
|
|
|
- `web.config` is not a substitute for NTFS permissions or placing private source outside webroot; verify both where practical. |
|
|
|
|
|
|
|
## 11. Error-handling contract |
|
|
|
- Local `On Error Resume Next` only around an operation whose `Err.Number` is immediately checked and cleared; otherwise use `On Error GoTo 0`. |
|
|
|
- Handle errors at the nearest layer that can add useful context or recover. Central HTTP boundary emits a safe 500 response if headers/body are not committed. |
|
|
|
- Define a testable strategy for already-committed responses. Never pretend an exception can undo a sent body. |
|
|
|
- Distinguish an expected not-found/validation result from a programmer/COM failure. |
|
|
|
|
|
|
|
## 12. Definition of done for each component |
|
|
|
1. Contract and source file exist; XML is well-formed. |
|
|
|
2. Public declarations match implemented functions/procedures and documented names. |
|
|
|
3. ProgID/CLSID identities are recorded and stable. |
|
|
|
4. Registration/unregistration is tested on Windows at the required bitness. |
|
|
|
5. WSH smoke test instantiates it where applicable; IIS HTTP integration runs when host objects are required. |
|
|
|
6. Failure path and cleanup are tested; no unmanaged mutable shared request state. |
|
|
|
7. Security review covers direct HTTP exposure and untrusted input. |
|
|
|
8. README or architecture docs reflect actual implementation, not intentions. |
|
|
|
9. Tests are reported as PASS, FAIL, or NOT RUN with commands, host details, and evidence. |
|
|
|
|
|
|
|
## 13. Milestone sequence and gates |
|
|
|
M0: Inspect repository/environment; record OS/IIS/ASP/bitness/permissions and missing tools. No claim of execution on Linux/macOS. |
|
|
|
M1: `Application.wsc` and `HomeController.wsc` register and instantiate; `/hello` returns expected 200/body; isolated WSH test where possible; registration is reversible. |
|
|
|
M2: Request/response context, central error mapping, per-request object lifetime; concurrent request smoke test. |
|
|
|
M3: Static route table, GET/POST method dispatch, 400/404/405 tests, safe URL handling. |
|
|
|
M4: Separate HTML templates and encoding tests; layout only after basic rendering passes. |
|
|
|
M5: ADODB connection lifecycle, parameterized queries, transactions, repository tests against an explicitly configured test DB. |
|
|
|
M6: Security, session/auth architecture, logging, deployment and concurrency hardening. |
|
|
|
M7: Scaffolding, repeatable tests, documentation, agent-guided quality improvements. |
|
|
|
Each milestone needs passing evidence before the next. Explicitly document any blocked milestone. |
|
|
|
|
|
|
|
## 14. Acceptance tests for M1 |
|
|
|
- `cscript //nologo tests\Test-Components.vbs` reports successful creation and expected method result (if the component's public API is host-independent). |
|
|
|
- `powershell -File tests\Test-Http.ps1 -BaseUrl http://localhost:<port>` verifies status, content type, and exact body for `/hello`. |
|
|
|
- Direct requests to WSC files and private directories are denied. |
|
|
|
- Missing ProgID or broken registration produces a safe 500; no filesystem path or raw internal exception is exposed. |
|
|
|
- Unregistration removes the project registrations only and is reversible by re-registration. |
|
|
|
- Test at least two concurrent HTTP requests; no cross-request leakage. |
|
|
|
- No tests are described as passed without actual output. |
|
|
|
|
|
|
|
## 15. Open questions to resolve experimentally |
|
|
|
- Can the proposed WSC Application COM method receive ASP intrinsic objects across this specific IIS/COM boundary reliably? If not, use a small ASP-host adapter and primitive arguments. |
|
|
|
- What exact registration tool and script-component XML forms work on the deployment OS and the relevant 32/64-bit host? |
|
|
|
- What is the safe reload/deployment procedure for an updated WSC under load? Do not promise hot reload before measuring it. |
|
|
|
- Which response contract best preserves error handling before bytes are sent? |
|
|
|
Record experiments, chosen behavior, tradeoffs, and evidence in `docs/DECISIONS.md`. |
|
|
|
|
|
|
|
## 16. Reference reading |
|
|
|
- Microsoft, Windows Script Components in IIS: https://learn.microsoft.com/en-us/previous-versions/iis/6.0-sdk/ms524594(v=vs.90) |
|
|
|
- Microsoft, Server.CreateObject: https://learn.microsoft.com/en-us/previous-versions/iis/6.0-sdk/ms524786(v=vs.90) |
|
|
|
- Microsoft, Setting Scope of COM Objects: https://learn.microsoft.com/en-us/previous-versions/iis/6.0-sdk/ms525036(v=vs.90) |
|
|
|
- Microsoft, Selecting a Threading Model: https://learn.microsoft.com/en-us/previous-versions/iis/6.0-sdk/ms525101(v=vs.90) |
|
|
|
- Microsoft, Classic ASP in IIS: https://learn.microsoft.com/en-us/iis/application-frameworks/running-classic-asp-applications-on-iis-7-and-iis-8/scenario-build-a-classic-asp-website-on-iis |
|
|
|
Archived documentation may describe older IIS/OS versions; experimentally validate modern OS behavior. |