Skip to content

BolMiddleware architecture

BolMiddleware is a net8.0 ASP.NET Core Razor class library shipped as a NuGet package. It gives consumer Razor Pages applications the Business Online (BOL) page chrome: shared layouts, menu and policy header view components, a chain of abstract PageModel base classes, and thin service facades over remote BOL, Policy, and SAIF platform API clients. Consumers adopt it by inheriting BolRazorLayoutStartup and deriving their pages from BolContextModel, BolMenuModel, or BolPolicyModel. The library has no host entry point and no database access; all persistence is delegated to remote APIs reached through internal client packages.

Responsibilities

  • Provide a startup base class (BolRazorLayoutStartup) that extends OidcRazorStartup, enables the legacy BOL authentication middleware, registers BOL services, and binds the BasicAppMap options.
  • Register BOL services and the four API client packages through RegisterBolServices.
  • Resolve and persist the BOL web context for every request through BolContextModel, using a short-lived cookie, the ASP.NET Core session, and the remote BOL Context API.
  • Load the BOL menu for the current user and drive cross-application navigation through BolMenuModel.
  • Load the policy header, validate access to the policy, and expose the policy association dropdown through BolPolicyModel.
  • Ship four Razor layouts, three view components, shared partials, a menu navigation script, and compiled styles as static web assets.
  • Offer optional consumer customization hooks as partial views under MiddlewareIncludes/.

Component boundaries

  • Host integration (BolRazorLayoutStartup, BolServiceExtensions): owns service registration and options binding; the middleware pipeline is inherited from OidcRazorStartup and is not defined here.
  • Page pipeline (BolContextModel, BolMenuModel, BolPolicyModel): abstract PageModels that form an inheritance chain and hook the Razor Pages handler filter events.
  • Service layer (BolServicesContainer, SecurityService, WebContextService, MenuService, PolicyHeaderService, CookieService, ContextCookieHelperService, RequestHelper): facades over the remote API clients and HTTP helpers; they catch exceptions and fall back to defaults.
  • Presentation (RCL views and view components): _PolicyLayout, _PolicyOnlyLayout, _ContextOnlyLayout, _MenuOnlyLayout, and the BolPolicyHeader, BolSideMenu, and BolTopMenu view components render data supplied by the PageModel.
  • Client script (wwwroot/js/MenuNavigation.js): intercepts menu link clicks and context box key presses and posts the context form for cross-application navigation.
  • Remote dependencies (outside this library): BOL Context API, BOL Menu API, Policy Header API, Policy Core API, the SAIF security client, and the SAIF environment client. Their endpoints and transport are package internals and unknown** from this repository.

Interaction model

  • A consumer page derives from a BolMiddleware PageModel. On handler selection the model reads the BolContext cookie and the ApplicationName setting.
  • On handler execution the model resolves the web context in priority order: cookie, referring application lookup, context id (cid query or WebContextId form value), then session.
  • State is held in three layers: the BolContext HttpOnly cookie (10 second lifetime), ASP.NET Core session JSON for the context, menu, and policy header, and the remote BOL Context API for cross-application persistence.
  • BolMenuModel loads the menu through IMenuService, and BolPolicyModel loads the policy header through IPolicyHeaderService and validates the policy through SecurityService, which calls IPolicyCoreApiClient.IsValidPolicyForUser. External user information comes from a different client: BolContextModel calls SecurityService.GetCurrentExternalUserAsync from OnPageHandlerExecuting, which calls ISecurityClient.GetExternalUser.
  • Layouts render the BOL chrome by invoking the view components with data from the PageModel.
  • Cross-application navigation hands the context off through a cid value or a referring application lookup.
  • Two sync-over-async calls exist in the page pipeline: the external user lookup in BolContextModel and the policy validation in BolPolicyModel.

Architecture diagram

The following diagram shows high-level component interactions.

flowchart TD
    Consumer[Consumer Razor Pages app] --> Startup[BolRazorLayoutStartup]
    Consumer --> Models[BolContextModel to BolMenuModel to BolPolicyModel]
    Startup --> Reg[RegisterBolServices]
    Models --> Container[BolServicesContainer]
    Models --> Facades[Context Menu PolicyHeader Security services]
    Models --> Cookie[Cookie and session state]
    Facades --> Clients[Internal API client packages]
    Clients --> Remote[BOL and Policy APIs]
    Models --> Layouts[Layouts and view components]
    Layouts --> Script[MenuNavigation.js]

Sequence diagram

The following diagram shows the primary request/response sequence.

sequenceDiagram
    participant Browser
    participant Page as Consumer page model
    participant Ctx as WebContextService
    participant Menu as MenuService
    participant Hdr as PolicyHeaderService
    Browser->>Page: GET page with cid or cookie
    Page->>Page: Read BolContext cookie and session
    Page->>Ctx: GetContext by context id or session
    Ctx-->>Page: Context result
    Page->>Menu: GetMenu for current user
    Menu-->>Page: Menu data
    Page->>Hdr: GetHeader for policy
    Hdr-->>Page: Policy header
    Page-->>Browser: Razor page with BOL layout

Design constraints

  • The library targets net8.0 only and requires the Microsoft.AspNetCore.App shared framework.
  • The startup pipeline order is inherited from OidcRazorStartup and is unknown** from this repository.
  • ISecurityClient, IEnvironmentClient, and ISaifLogService are resolved but not registered here; they are expected from the base startup*.
  • AddSession() is called, but UseSession() and a distributed cache are not configured in this library; whether the base startup enables session middleware is unknown**.
  • IBolContextApiClient is registered twice; the last registration wins for single resolution.
  • IAppMap resolves a default BasicAppMap instance, while views read the configured IOptions<BasicAppMap> directly.
  • Singleton facades depend on API clients whose lifetimes are set inside the packages, so a lifetime capture risk is unknown**.
  • View component InvokeAsync methods are declared async but contain no await.

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts. Statements marked with ** could not be confirmed; treat as unknown until verified.

Sources

  • src/BolMiddleware/BolMiddleware.csproj
  • src/BolMiddleware/BolRazorLayoutStartup.cs
  • src/BolMiddleware/Extensions/BolMiddlewareExtensions.cs
  • src/BolMiddleware/Models/BolContextModel.cs
  • src/BolMiddleware/Models/BolMenuModel.cs
  • src/BolMiddleware/Models/BolPolicyModel.cs
  • src/BolMiddleware/Services/BolServicesContainer.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/ViewComponents/BolPolicyHeaderViewComponent.cs
  • src/BolMiddleware/Pages/Shared/_PolicyLayout.cshtml
  • src/BolMiddleware/wwwroot/js/MenuNavigation.js