---
title: SAIF.Presentation.Web.MVC business rules
summary: Enumerated business rules with per-rule trigger, enforcement, and outcomes.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-08-17
library: SAIF.Presentation.Web.MVC
reference_type: package
---

# SAIF.Presentation.Web.MVC business rules

This page captures business rules enforced by this library.

## BR-MVC-001: Session timeout treated as an unprocessable postback

| Field | Value |
| --- | --- |
| **Statement** | A postback arriving on a new session is treated as a timed-out session and must not be processed. |
| **Trigger** | `Initialize` on every request |
| **Enforcement** | `clsControllerBase.IsSessionTimedOut`, `Initialize` |
| **Outcome** | Request is redirected instead of executed |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-002: Internal users are returned to the app landing page on timeout

| Field | Value |
| --- | --- |
| **Statement** | Internal users whose session timed out return to the application's landing page with an explanatory message. |
| **Trigger** | Session timeout, caller address matches `10.*`, `131.131.*.*`, or `127.0.0.1` |
| **Enforcement** | `clsControllerBase.Initialize`, `IsInsideClient` |
| **Outcome** | Redirect to `/<AppName>?MSG=Your session has timed out.` |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-003: External users are sent to the login screen on timeout

| Field | Value |
| --- | --- |
| **Statement** | External users whose session timed out have their authentication cookie cleared and are sent to the online login screen. |
| **Trigger** | Session timeout, non-internal address |
| **Enforcement** | `clsControllerBase.Initialize` |
| **Outcome** | `SAIFAUTH` cookie blanked; redirect to `/OnlineLogin/LoginScreen.aspx` |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-004: Every request carries a single established security principal

| Field | Value |
| --- | --- |
| **Statement** | Each request must carry an authenticated security principal on the model context; the principal is established once and reused. |
| **Trigger** | `SecurityCheck` during initialization |
| **Enforcement** | `clsControllerBase.SecurityCheck` |
| **Outcome** | Context holds a `clsSecurityPrincipal`; `STYPE` cookie carries the upper-cased user name |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-005: Unauthenticated callers are challenged or refused by network zone

| Field | Value |
| --- | --- |
| **Statement** | Unauthenticated internal callers are challenged for Windows/Basic credentials; unauthenticated external callers are refused. |
| **Trigger** | `SecurityCheck` when the principal is not authenticated |
| **Enforcement** | `clsControllerBase.SecurityCheck` (`clsEnvironment.InternalAddress`) |
| **Outcome** | 401 with `WWW-Authenticate: NTLM` and `Basic realm="SAIF"`, or `Exception("Not Authorized.")` |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-006: The authorized menu set is loaded once per session

| Field | Value |
| --- | --- |
| **Statement** | The user's authorized menu set is loaded once per session and cached under session key `navdata`. |
| **Trigger** | First request of a session |
| **Enforcement** | `clsControllerBase.Initialize` |
| **Outcome** | One Oracle menu load per session |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-007: Page access requires menu authorization

| Field | Value |
| --- | --- |
| **Statement** | A user may only reach a page that appears in their authorized menu for the current application; otherwise they are returned to the login screen. |
| **Trigger** | Every request, after `SecurityCheck` |
| **Enforcement** | `clsControllerBase.RedirectUnauthorizedUsers` → `NavigationContext.IsMenuItem` |
| **Outcome** | Cached `navdata` cleared and redirect to `/OnlineLogin/LoginScreen.aspx` |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-008: Multi-model view state is keyed by a per-view GUID

| Field | Value |
| --- | --- |
| **Statement** | When multi-model support is enabled, each open view has a distinct GUID view ID that keys its model and view data in session, carried across requests in the `__SAIFPID` hidden field/query string. |
| **Trigger** | Page render, navigation, postback |
| **Enforcement** | `ViewPageBase.ViewID`, `clsControllerBase.Model`/`ViewData`/`Navigate` |
| **Outcome** | Multiple browser windows on the same session keep independent state |
| **Tables** | [Context](database-tables.md#context) |
| **SQL** | [SQL-003](sql/SQL-003-retrieve-context-value-by-name.md) |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-009: Absolute navigation targets are preserved verbatim

| Field | Value |
| --- | --- |
| **Statement** | A navigation target that starts with `HTTP` or `/` is used verbatim; anything else is composed as `/<app>/<view>`. |
| **Trigger** | `Navigate` |
| **Enforcement** | `clsControllerBase.Navigate` |
| **Outcome** | Absolute and cross-site targets are preserved |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-010: Every navigation records source/target app and view

| Field | Value |
| --- | --- |
| **Statement** | Every navigation records source app, source view, target app, and target view in the context so the destination screen can react to where the user came from. |
| **Trigger** | `Navigate` |
| **Enforcement** | `clsControllerBase.Navigate`, consumed in `CheckContext` |
| **Outcome** | Destination applies the values through `HandleContext` and completes deferred navigation |
| **Tables** | [Context](database-tables.md#context) |
| **SQL** | [SQL-001](sql/SQL-001-insert-context-row.md), [SQL-002](sql/SQL-002-retrieve-context-rows.md) |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-011: Context is persisted only on genuine cross-app transitions

| Field | Value |
| --- | --- |
| **Statement** | Context is persisted to the shared store only when leaving the current application, and never when the session has already timed out; `Navigate2` requires multi-model support. |
| **Trigger** | Cross-application `Navigate`; any `Navigate2` call |
| **Enforcement** | `clsControllerBase.Navigate`, `Navigate2` |
| **Outcome** | Context rows written only for genuine cross-app transitions; `ApplicationException` otherwise |
| **Tables** | [Context](database-tables.md#context) |
| **SQL** | [SQL-001](sql/SQL-001-insert-context-row.md) |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-012: Redirect-induced thread aborts are suppressed

| Field | Value |
| --- | --- |
| **Statement** | Redirect-induced thread aborts must be suppressed so they are not reported as application errors. |
| **Trigger** | Any `Response.Redirect` in the framework |
| **Enforcement** | `clsControllerBase.Initialize`, `Navigate`, `HandleErrors` (`Thread.ResetAbort`) |
| **Outcome** | No spurious `ThreadAbortException` reaches error handling |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-013: Popup navigation uses a fixed window geometry

| Field | Value |
| --- | --- |
| **Statement** | Popup navigation opens a fixed-geometry window (505×641 at 10,10, no menu/toolbar/scrollbars/resize by default) and focuses either the child window or the opener. |
| **Trigger** | `Navigate` with `Popup = True` |
| **Enforcement** | `clsControllerBase.Navigate` popup script |
| **Outcome** | Consistent popup presentation across screens |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-014: The authenticated user name is exposed via the STYPE cookie

| Field | Value |
| --- | --- |
| **Statement** | The authenticated user name is exposed to the browser in the `STYPE` cookie in upper case. |
| **Trigger** | Successful `SecurityCheck` |
| **Enforcement** | `clsControllerBase.SecurityCheck` |
| **Outcome** | Client-side code can read the current user identity |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-015: Menu authorization data is read from Oracle as user MENU

| Field | Value |
| --- | --- |
| **Statement** | Menu authorization data is read from Oracle as database user `MENU` using the environment's configured Oracle connection, keyed by the trimmed upper-cased user ID. |
| **Trigger** | `NavigationContext` construction |
| **Enforcement** | `NavigationContext.New` |
| **Outcome** | Authorized items reflect that user's menu grants |
| **Source** | SAIF.Presentation.Web.MVC/NavigationContext.vb |

---

## BR-MVC-016: A model initializes exactly once per instance

| Field | Value |
| --- | --- |
| **Statement** | A model initializes exactly once per instance, and loading preferences for the user/application is part of that initialization. |
| **Trigger** | `Model.Pre_Init` during `Initialize` |
| **Enforcement** | `clsModelBase.Pre_Init` (`m_Inited` guard) |
| **Outcome** | `Initialize()` and `clsPreferences` construction happen once |
| **Source** | SAIF.Presentation.Web.MVC/clsModelBase.vb |

---

## BR-MVC-017: Cross-application context is consumed exactly once

| Field | Value |
| --- | --- |
| **Statement** | Cross-application context is consumed exactly once: rows are deleted after retrieval, and re-saving an application's context first clears the previous rows. |
| **Trigger** | `RetrieveContext`, `SaveContext` |
| **Enforcement** | `clsContext.RetrieveContext`, `clsContext.SaveContext`, `clsContextRepository.Delete` |
| **Outcome** | No stale context leaks into later navigations |
| **Tables** | [Context](database-tables.md#context) |
| **SQL** | [SQL-002](sql/SQL-002-retrieve-context-rows.md), [SQL-004](sql/SQL-004-delete-context-rows.md) |
| **Source** | SAIF.Presentation.Web.MVC/clsContext.vb |

---

## BR-MVC-018: Reference-data caches are process-lifetime, not per-session

| Field | Value |
| --- | --- |
| **Statement** | Application codes and menu categories are cached for the process lifetime rather than per user or per session. |
| **Trigger** | First access to `ApplicationCodes` / `MenuCategories` |
| **Enforcement** | `NavigationContext.GetApplicationCodes`, `GetMenuCategories` (`Static` locals) |
| **Outcome** | Reference data is fetched once per application domain; changes require a recycle |
| **Source** | SAIF.Presentation.Web.MVC/NavigationContext.vb |

---

## BR-MVC-019: Context persistence targets database APPM under tag NETFRAMEWORK

| Field | Value |
| --- | --- |
| **Statement** | Context persistence runs against the configured .NET-Framework SQL Server instance using database `APPM` under the `NETFRAMEWORK` application tag. |
| **Trigger** | Any context repository operation |
| **Enforcement** | `clsContext.clsContextRepository` (`clsConnection.getConnection`) |
| **Outcome** | All context I/O is routed through the framework connection factory |
| **Tables** | [Context](database-tables.md#context) |
| **SQL** | [SQL-001](sql/SQL-001-insert-context-row.md), [SQL-002](sql/SQL-002-retrieve-context-rows.md), [SQL-003](sql/SQL-003-retrieve-context-value-by-name.md), [SQL-004](sql/SQL-004-delete-context-rows.md) |
| **Source** | SAIF.Presentation.Web.MVC/clsContext.vb |

---

## BR-MVC-020: Posted control values are harvested by recognized type

| Field | Value |
| --- | --- |
| **Statement** | On every postback the framework harvests the current value of every recognized input control on the page into a name/value map for the screen's `Retrieve` implementation. |
| **Trigger** | `Page_Load` → `CallRetrieve` |
| **Enforcement** | `clsControllerBase.GetInControls` |
| **Outcome** | Derived controllers receive posted values without per-control plumbing |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-021: Vendor/SAIF controls are recognized by type name, not assembly reference

| Field | Value |
| --- | --- |
| **Statement** | Vendor and SAIF controls are recognized by type name and read reflectively, so the framework does not take a compile-time dependency on the vendor assemblies. |
| **Trigger** | Control harvesting and focus binding |
| **Enforcement** | `clsControllerBase.GetInControls`, `ViewPageBase.NavigationManager.BoundControlId` |
| **Outcome** | Infragistics/SAIF controls participate without an assembly reference; unknown types are ignored |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-022: Applications may self-handle exceptions

| Field | Value |
| --- | --- |
| **Statement** | An application may handle its own exceptions by overriding `HandleApplicationError` and returning `True`, which suppresses framework error routing. |
| **Trigger** | Unhandled page exception |
| **Enforcement** | `ViewPageBase.ProcessError` |
| **Outcome** | Framework logging/redirect is bypassed for application-handled errors |
| **Source** | SAIF.Presentation.Web.MVC/ViewPageBase.aspx.vb |

---

## BR-MVC-023: Database timeout/unavailable errors show a retryable message

| Field | Value |
| --- | --- |
| **Statement** | Database timeout and database-unavailable exceptions are shown to the user as retryable messages on the page and then routed to the application's default view. |
| **Trigger** | `ProcessError` with a `clsSAIFException` of the matching type |
| **Enforcement** | `ViewPageBase.ProcessError` |
| **Outcome** | Message control text set, error logged, navigation to `Default.aspx?MSG=…` |
| **Source** | SAIF.Presentation.Web.MVC/ViewPageBase.aspx.vb |

---

## BR-MVC-024: Every framework-handled error is logged and e-mailed to support

| Field | Value |
| --- | --- |
| **Statement** | Every framework-handled error is logged and e-mailed to the configured support distribution list. |
| **Trigger** | `HandleErrors` |
| **Enforcement** | `clsControllerBase.HandleErrors` (`clsLogError.CreateErrorWithEmail`) |
| **Outcome** | Support receives the error with model and context detail |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-025: The error page falls back by network zone when unconfigured

| Field | Value |
| --- | --- |
| **Statement** | The error page is taken from configuration when present; otherwise internal callers get the intranet error page and external callers the public HTTPS error page. |
| **Trigger** | `HandleErrors` |
| **Enforcement** | `clsControllerBase.HandleErrors` (`AppSettings("ErrorPageName")`) |
| **Outcome** | Users always land on an appropriate error page |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-026: Error messages are HTML-encoded before redirect

| Field | Value |
| --- | --- |
| **Statement** | Error messages placed on the error-page query string are HTML-encoded with line breaks removed. |
| **Trigger** | `HandleErrors` |
| **Enforcement** | `clsControllerBase.HandleErrors` (`HttpUtility.HtmlEncode`) |
| **Outcome** | Message content cannot inject markup into the error page |
| **Source** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

---

## BR-MVC-027: Focus is restored to the last bound control by control family

| Field | Value |
| --- | --- |
| **Statement** | After a postback the browser returns focus to the last bound control, using the focus API appropriate to that control family. |
| **Trigger** | `PreRender` when a bound control ID is in session |
| **Enforcement** | `ViewPageBase.NavigationManager` |
| **Outcome** | Keyboard focus is preserved across postbacks |
| **Source** | SAIF.Presentation.Web.MVC/ViewPageBase.aspx.vb |

---

## BR-MVC-028: Focus restoration failures never break the page

| Field | Value |
| --- | --- |
| **Statement** | Focus restoration must never break the page. |
| **Trigger** | Client `load` event |
| **Enforcement** | Generated `MyFunction` `try`/`catch` |
| **Outcome** | Focus failures are silently ignored |
| **Source** | SAIF.Presentation.Web.MVC/ViewPageBase.aspx.vb |

---

## BR-MVC-029: A model is written only after its own validation succeeds

| Field | Value |
| --- | --- |
| **Statement** | A model is written only after its own validation succeeds. |
| **Trigger** | `clsControllerBase.Write` / `clsModelBase.Write` |
| **Enforcement** | `clsModelBase.Write` |
| **Outcome** | `WriteData` runs only when `ValidateData` returns `True` |
| **Source** | SAIF.Presentation.Web.MVC/clsModelBase.vb |

---

## BR-MVC-030: View state may be moved into session for external/all users

| Field | Value |
| --- | --- |
| **Statement** | View state may be moved from the page into session for external users (or all users) when explicitly enabled, with `10.*` addresses treated as internal. |
| **Trigger** | Page state persistence |
| **Enforcement** | `ViewPageBase.PageStatePersister` (`ViewStateInSession`, `EXT_VIEWSTATE_SESSION`) |
| **Outcome** | External clients receive smaller pages; state is held server-side |
| **Source** | SAIF.Presentation.Web.MVC/ViewPageBase.aspx.vb |

---

## BR-MVC-031: Validation helpers define consistent invalidity semantics

| Field | Value |
| --- | --- |
| **Statement** | Validation helpers treat a `Nothing` or whitespace-only string as invalid, a non-numeric string as an invalid number, a non-date string as an invalid date, and a date on or before today as not a future date. |
| **Trigger** | Derived model validation |
| **Enforcement** | `clsModelBase.IsValidString`, `IsValidNumber`, `IsValidDate`, `IsValidFutureDate` |
| **Outcome** | Consistent validation semantics across all screens |
| **Source** | SAIF.Presentation.Web.MVC/clsModelBase.vb |

---

## BR-MVC-032: Every page discloses the serving machine name

| Field | Value |
| --- | --- |
| **Statement** | Every rendered page carries the serving machine name in an HTML comment for support diagnostics. |
| **Trigger** | `Page_Init` outside design mode |
| **Enforcement** | `ViewPageBase.Page_Init` (`SAIF_SOURCE` script block) |
| **Outcome** | Support can identify the serving web server from page source |
| **Source** | SAIF.Presentation.Web.MVC/ViewPageBase.aspx.vb |

---

## BR-MVC-033: A tracing banner is shown when tracing is enabled

| Field | Value |
| --- | --- |
| **Statement** | When tracing is enabled, the page displays a fixed "TRACING IS ENABLED" banner and turns on ASP.NET trace output. |
| **Trigger** | `PreRender` when `clsLogTrace.IsEnabled` / `UserTraceEnabled` |
| **Enforcement** | `ViewPageBase.Page_PreRender` |
| **Outcome** | Users and support can see that tracing is active |
| **Source** | SAIF.Presentation.Web.MVC/ViewPageBase.aspx.vb |

---

## Inherited business rules

Rules in this section originate from base classes or services provided by dependency framework libraries. They are enforced by inherited behavior, not by code in this library. This library does not itself derive from `clsBusinessBase`, but the run's library-density scan detected the `clsBusinessBase` base-class reference in this library's dependency chain; the rule below is recorded for cross-layer traceability with `SAIF.Business.Menu`, whose object model derives from `clsBusinessBase`. The originating class and library are recorded in the rule's **Origin** field.

## INH-MVC-001: Business rule violations are tracked in a broken-rules collection

| Field | Value |
| --- | --- |
| **Statement** | `clsBusinessBase` evaluates registered rules through a `clsRulesManager` and records rule failures in a broken-rules collection; validation state is surfaced through `IDataErrorInfo` so `IsValid` becomes `False` while broken rules exist.† |
| **Trigger** | Property changes or lifecycle methods on a business object derived from `clsBusinessBase`.† |
| **Enforcement** | `clsRulesManager` (`clsBusinessBase`)† |
| **Outcome** | UI/data-binding consumers observe validation errors via `IDataErrorInfo` until the broken-rule condition clears.† |
| **Origin** | `SAIF.Framework.Core` — `clsBusinessBase` |
| **Source** | Retrieved from indexed documentation via Legends CLI |

---

## Notes
- Mark inferred statements with `*` and unknown statements with `**`. Do not use bold inline confidence labels.
- Statements marked with `†` were retrieved from dependency library documentation via the Legends CLI RAG service.
- `INH-MVC-001` describes behavior owned by `clsBusinessBase` in `SAIF.Framework.Core`; it is retained here for cross-layer traceability because this library's dependency `SAIF.Business.Menu` derives from it. This library's own classes do not inherit from `clsBusinessBase`.

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Dependencies](dependencies.md)
- [Operations and processes](operations-processes.md)
- [Database tables](database-tables.md)
- [SQL catalog](sql/index.md)
- [Configuration](configuration.md)
- [Security and authorization](security-authorization.md)
- [API reference](api/index.md)

> **Note:** Statements marked with `†` are derived from dependency library documentation via the Legends CLI. They describe inherited behavior from the indicated origin library and should be verified if the dependency version changes.

## Sources
- SAIF.Presentation.Web.MVC/clsControllerBase.vb
- SAIF.Presentation.Web.MVC/clsContext.vb
- SAIF.Presentation.Web.MVC/clsModelBase.vb
- SAIF.Presentation.Web.MVC/NavigationContext.vb
- SAIF.Presentation.Web.MVC/ViewPageBase.aspx.vb
