Skip to content

BolMiddleware business rules

This page lists the behavioral rules that BolMiddleware enforces on every consumer Razor Page. Each rule has its own section with a Field/Value table. Rules are enforced by the abstract page model chain (BolContextModel, BolMenuModel, BolPolicyModel), the service facades, and the shared Razor views. The library holds no database tables, so no rule has a table or SQL source.

BR-BOLMIDDLEWARE-001 Web context resolution precedence

Field Value
Statement The BOL web context for a request is resolved from the first available source in this order: the BolContext cookie, a re-read of the cookie, the referring application, the WebContextId form value or cid query value, the session, and finally a newly created context.
Trigger Every Razor Page handler selection on a page that derives from BolContextModel.
Enforcement BolContextModel.OnPageHandlerExecuting calls TryGetContext, which calls WebContextService.GetContext and NewContext through the request helper. The cookie is read earlier, in OnPageHandlerSelected.
Outcome WebContext is populated for the handler. When no source yields a context a new context is created, the middleware session cookie is added, and the BolContext cookie is set.
Source src/BolMiddleware/Models/BolContextModel.cs

BR-BOLMIDDLEWARE-002 Context save condition

Field Value
Statement The context is written to the cookie whenever it has content. It is saved through the remote BOL Context API only when the caller forces the save or the target application differs from the current application. It is always saved to the session.
Trigger A consumer page calls SaveContext, or navigation calls it while moving to another application.
Enforcement BolContextModel.SaveContext(bool forceSave) evaluates the cookie, API, and session writes independently.
Outcome The API call is skipped for same-application requests unless forceSave is true; the session copy is always refreshed.
Source src/BolMiddleware/Models/BolContextModel.cs

BR-BOLMIDDLEWARE-003 Context content detection

Field Value
Statement A context has content when it has an Id. A context with no Id but with a session id is given a newly generated GUID as its Id and counts as having content.
Trigger Any call to HasContent before saving or cookie writing.
Enforcement WebContextExtensions.HasContent mutates the ContextResult.Id as a side effect.
Outcome A check for content can mint an Id; a context with neither Id nor session id has no content and is not persisted.
Source src/BolMiddleware/Services/Context/WebContextExtensions.cs

Field Value
Statement The BolContext cookie lives for ten seconds and is flagged HttpOnly. It carries no Secure or SameSite attribute. Its expiry is computed from the local server clock.
Trigger Context creation and every context save that writes the cookie.
Enforcement CookieService.SetCookie and SetCookieObject build CookieOptions with HttpOnly = true and an Expires value from DateTime.Now.
Outcome The cookie works as a short hand-off between consecutive requests during cross-application navigation. It is sent over HTTP and cross-site requests if the host permits.
Source src/BolMiddleware/Services/CookieService/CookieService.cs, src/BolMiddleware/Models/BolContextModel.cs

BR-BOLMIDDLEWARE-005 External user detection

Field Value
Statement A user is external when the domain portion of the authenticated identity name is not SAIF.
Trigger Any read of IsUserExternal or any call to ISecurityService.IsUserExternal.
Enforcement SecurityService.IsUserExternal splits the identity name on the domain separator and compares the domain with SAIF.
Outcome External users get the external user branch of context, policy header, and header link logic; internal users get the internal branch.
Source src/BolMiddleware/Services/Security/SecurityService.cs

BR-BOLMIDDLEWARE-006 External user information lookup once

Field Value
Statement External user information is requested from the security client (ISecurityClient.GetExternalUser) only while the context cookie user state is New. After a successful lookup the state becomes Validated. The Policy Core API is not involved in this lookup; it is used only for policy access validation (BR-BOLMIDDLEWARE-009).
Trigger A request from an external user where the cookie user state is New.
Enforcement BolContextModel.OnPageHandlerExecuting calls GetExternalUserInformationForContext, which calls SecurityService.GetCurrentExternalUserAsync once and updates contextCookie.userState and userType. Exceptions are swallowed.
Outcome Later requests inside the cookie lifetime reuse the stored user type and state without calling the security client again.
Source src/BolMiddleware/Models/BolContextModel.cs, src/BolMiddleware/Services/Security/SecurityService.cs

BR-BOLMIDDLEWARE-007 Menu source selection

Field Value
Statement The menu is read from the session when present. Otherwise it is requested from the BOL Menu API for the current user and stored in the session. When the API returns nothing the menu stays empty.
Trigger Handler execution on a page that derives from BolMenuModel.
Enforcement BolMenuModel.OnPageHandlerExecuting checks the session before calling MenuService.GetMenu.
Outcome MenuData is the session copy, the API copy, or the default empty menu.
Source src/BolMiddleware/Models/BolMenuModel.cs, src/BolMiddleware/Services/Menu/MenuService.cs

BR-BOLMIDDLEWARE-008 Context value classification

Field Value
Statement A posted context value whose length is less than seven or exactly nine characters is treated as a policy number. Any other length is treated as a claim number.
Trigger A user submits the context textbox with a new value on a page with the context field.
Enforcement BolMenuModel.OnPageHandlerExecuting inspects ContextValue.Length and stores it under the policy or claim context item.
Outcome The context is updated with a policy number or claim number before the page continues.
Source src/BolMiddleware/Models/BolMenuModel.cs

BR-BOLMIDDLEWARE-009 Policy access validation

Field Value
Statement Access to a policy is validated for the current user through IsValidPolicyForCurrentUser. The result is read synchronously and drives the AccessAllowed flag.
Trigger A policy header page resolves a policy number.
Enforcement BolPolicyModel.GetPolicyHeader reads Task.Result of the validation call and sets AccessAllowed and ErrorMessage.
Outcome Failed validation sets an error message so that the view renders the error view. Enforcement is soft: derived pages must check AccessAllowed themselves.
Source src/BolMiddleware/Models/BolPolicyModel.cs, src/BolMiddleware/Services/Security/SecurityService.cs

BR-BOLMIDDLEWARE-010 Parent account reset

Field Value
Statement ParentAccount is reset to zero, and the stored ParentAccount context value is set to 0, only when the posted contextvalue (the policy select value from the context textbox) is non-empty, meaning a new policy was entered. When it is empty the reset does not occur. Afterwards TryGetPolicyHeader restores ParentAccount from the context value when that value is greater than zero, and derives it from the header (BR-BOLMIDDLEWARE-011) only while ParentAccount is zero.
Trigger BolPolicyModel.OnPageHandlerExecuting with a non-empty posted contextvalue.
Enforcement The handler assigns ParentAccount = 0 and calls WebContext.SetContextValue("ParentAccount", "0") inside an if (!string.IsNullOrEmpty(policyselect)) block, before header resolution.
Outcome Entering a new policy discards the earlier parent account. Requests without a posted contextvalue keep any stored parent account greater than zero.
Source src/BolMiddleware/Models/BolPolicyModel.cs

BR-BOLMIDDLEWARE-011 Parent account derivation

Field Value
Statement The parent account is taken from the policy header relationship policy, or from the rate account when no relationship policy is present.
Trigger A policy header is resolved for a valid policy.
Enforcement BolPolicyModel.GetPolicyHeader reads RelationshipPolicy and RateAccount from the header.
Outcome ParentAccount exposes the numeric parent account to the consumer page.
Source src/BolMiddleware/Models/BolPolicyModel.cs

BR-BOLMIDDLEWARE-012 Policy dropdown visibility

Field Value
Statement The dropdown is shown only when the header has at least one association and one of these conditions holds. External user: the web context CustomerId is non-empty and equals the header relationship policy or rate account, or the header has a ManualAffiliation association and CustomerId equals ParentAccount. Internal user: the header policy number equals the rate account or relationship policy, or ParentAccount equals the relationship policy or rate account. No minimum of two associations is required.
Trigger After a policy header is resolved.
Enforcement BolPolicyModel.CanViewPolicyDropdown(isUserExternal) sets ShowPolicyDropdown; BolPolicyHeader view renders either the select or a plain label.
Outcome Eligible users can switch policy from the header; others see the policy number and name only. This is a presentation gate; a chosen policy is re-validated by policy access validation.
Source src/BolMiddleware/Models/BolPolicyModel.cs, src/BolMiddleware/Pages/Components/BolPolicyHeader/default.cshtml

BR-BOLMIDDLEWARE-013 External association filtering

Field Value
Statement The Policy Header API is called with the policy number and an external-user flag (true when the web context customer id is greater than zero). For an external user, user type code POLCY replaces the header associations with those returned by a second header lookup for the customer id; user type code AGNCY keeps only associations that contain a policy whose AgencyId equals the customer id. Any other user type code leaves the associations unchanged.
Trigger The policy header is requested through IPolicyHeaderService.GetHeader with a customer id greater than zero.
Enforcement PolicyHeaderService.GetHeader switches on the user type code after IPolicyHeaderApiClient.GetHeader(policyNumber, isExternalUser).
Outcome The dropdown offers the customer's policies for POLCY, the agency's policies for AGNCY, and the unfiltered associations otherwise. The customer id and type code come from the web context, not from the identity on each request.
Source src/BolMiddleware/Services/Headers/Policy/PolicyHeaderService.cs

BR-BOLMIDDLEWARE-014 Session policy header reuse

Field Value
Statement A policy header stored in the session is reused when it matches the requested policy number; otherwise the header is requested from the API and saved to the session.
Trigger TryGetPolicyHeader on a policy header page.
Enforcement BolPolicyModel.TryGetPolicyHeader compares the session header's policy number with the context policy number.
Outcome API calls are avoided for repeated requests on the same policy.
Source src/BolMiddleware/Models/BolPolicyModel.cs

BR-BOLMIDDLEWARE-015 Policy dropdown ordering

Field Value
Statement Dropdown entries are ordered by policy number descending, with the currently selected policy moved to the first position. Each policy number may appear only once.
Trigger The BolPolicyHeader view renders the dropdown.
Enforcement HeaderExtensions.GetPolicyAssociationDropdown sorts, moves the current policy, and fills a dictionary using Add.
Outcome A duplicate policy number across associations throws an ArgumentException while the view renders.
Source src/BolMiddleware/Extensions/HeaderExtensions.cs

BR-BOLMIDDLEWARE-016 Null menu error view

Field Value
Statement When no menu object is available the side menu view component returns the shared error view.
Trigger BolSideMenu or BolTopMenu is invoked with a null menu.
Enforcement The view component InvokeAsync methods return the Error view when the menu is null.
Outcome The page shows an error banner in place of the menu.
Source src/BolMiddleware/ViewComponents/BolSideMenuViewComponent.cs, src/BolMiddleware/ViewComponents/BolTopMenuViewComponent.cs

BR-BOLMIDDLEWARE-017 Error message error view

Field Value
Statement When the policy model carries an error message the policy header view component returns the shared error view with that message.
Trigger BolPolicyHeader is invoked with a non-empty error message.
Enforcement BolPolicyHeaderViewComponent.InvokeAsync returns View("Error", errorMessage).
Outcome The page renders the message text in the error banner. Exception messages set by BolPolicyModel are shown as-is.
Source src/BolMiddleware/ViewComponents/BolPolicyHeaderViewComponent.cs, src/BolMiddleware/Pages/Shared/Error.cshtml

Field Value
Statement Profile and logoff links in the page header appear only for external users. The target host is account.saif.com when the environment name contains prod and account-qa.saif.com otherwise.
Trigger The _BolPageHeaderPartial renders for an external user.
Enforcement The partial checks Model.IsUserExternal and IWebHostEnvironment.EnvironmentName.
Outcome External users get profile and logoff navigation; internal users get none. An environment such as preprod also matches the production host.
Source src/BolMiddleware/Pages/Shared/_BolPageHeaderPartial.cshtml

BR-BOLMIDDLEWARE-019 Context textbox visibility

Field Value
Statement The context textbox in the layouts is rendered as a visible text input when the page sets ChangeContextPrivilege, and as a hidden input otherwise. This is a presentation behavior only, not server-side authorization.
Trigger A layout renders the web context form.
Enforcement The layouts test ChangeContextPrivilege on the page model to choose type="text" or type="hidden". BolMenuModel reads the posted contextvalue without checking the flag.
Outcome Hiding the input does not stop a crafted form post from changing the policy or claim context. The library never assigns the flag; the consuming application sets it.
Source src/BolMiddleware/Pages/Shared/_PolicyLayout.cshtml, src/BolMiddleware/Pages/Shared/_ContextOnlyLayout.cshtml

BR-BOLMIDDLEWARE-020 Session identifier source selection

Field Value
Statement The session id used for context lookups comes from a named cookie when the environment key bolmiddleware:UseSessionCookie is true, and from the ASP.NET Core session otherwise.
Trigger Every request through BolContextModel that needs a session id.
Enforcement BolContextModel.GetSessionId reads IEnvironmentClient.GetSettingValue for bolmiddleware:UseSessionCookie on every call, and reads bolmiddleware:SessionCookieName there only when UseSessionCookie is true. SessionCookieName is also read separately when a new context is created and AddMiddlewareSessionCookie appends the session cookie.
Outcome Applications behind a shared session cookie can share a context. Missing-key behavior is unknown**.
Source src/BolMiddleware/Models/BolContextModel.cs

BR-BOLMIDDLEWARE-021 Silent failure degradation

Field Value
Statement Failures in the remote context, menu, and policy header services are logged and replaced by empty or default results instead of being thrown to the page.
Trigger An API client exception inside WebContextService, MenuService, or PolicyHeaderService.
Enforcement Each facade wraps client calls in try and catch blocks that log through ISaifLogService and return a default value.
Outcome Pages render with a missing menu or context rather than failing; operators learn of faults only from the logs.
Source src/BolMiddleware/Services/Context/WebContextService.cs, src/BolMiddleware/Services/Menu/MenuService.cs, src/BolMiddleware/Services/Headers/Policy/PolicyHeaderService.cs

Notes

  • Rules 009 and 021 combine to give soft enforcement: a failed access check or a failed API call never stops the page from running.
  • The UserType record and the WebContextSaveKey constant are defined but unused; no rule depends on them.

Note: Statements marked with ** could not be confirmed; treat as unknown until verified.

Sources

  • src/BolMiddleware/Models/BolContextModel.cs
  • src/BolMiddleware/Models/BolMenuModel.cs
  • src/BolMiddleware/Models/BolPolicyModel.cs
  • src/BolMiddleware/Services/CookieService/CookieService.cs
  • src/BolMiddleware/Services/Context/WebContextExtensions.cs
  • src/BolMiddleware/Services/Context/WebContextService.cs
  • src/BolMiddleware/Services/Menu/MenuService.cs
  • src/BolMiddleware/Services/Headers/Policy/PolicyHeaderService.cs
  • src/BolMiddleware/Services/Security/SecurityService.cs
  • src/BolMiddleware/Extensions/HeaderExtensions.cs
  • src/BolMiddleware/ViewComponents/BolPolicyHeaderViewComponent.cs
  • src/BolMiddleware/ViewComponents/BolSideMenuViewComponent.cs
  • src/BolMiddleware/ViewComponents/BolTopMenuViewComponent.cs
  • src/BolMiddleware/Pages/Shared/_BolPageHeaderPartial.cshtml
  • src/BolMiddleware/Pages/Shared/_PolicyLayout.cshtml
  • src/BolMiddleware/Pages/Shared/_ContextOnlyLayout.cshtml
  • src/BolMiddleware/Pages/Shared/Error.cshtml
  • src/BolMiddleware/Pages/Components/BolPolicyHeader/default.cshtml