---
title: Build and attach the Business Online menu
summary: Populate the current view model's menu, decorating it with the active item, category, and user status.
status: draft
owner: SAIF Documentation
last_reviewed: 2026-09-17
library: SAIF.Framework.Web.Mvc
reference_type: package
operation_id: OP-11
trigger: After every action on a controller derived from `MenuControllerBase`
---

# Build and attach the Business Online menu

Populate the current view model's menu, decorating it with the active item, category, and user status. Trigger: After every action on a controller derived from `MenuControllerBase`.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-11 |
| **Trigger** | After every action on a controller derived from `MenuControllerBase` |
| **Inputs** | `ViewData.Model`, `User.Identity.Name`, request URL, `HttpContext.Session["BusinessOnlineMenu"]` |
| **Outputs** | `MenuViewModelBase.Menu` fully populated |
| **Primary components** | `MenuControllerBase.OnActionExecuted(ActionExecutedContext)`, private `Menu` property, private `GetCurrentItemId` |
| **Entry point** | `src/Web.Mvc/Controllers/MenuControllerBase.cs` |

## Steps

1. `Enforce.ArgumentNotNull(filterContext, "filterContext")` ([BR-01](../business-rules.md#br-01-guarded-arguments-reject-null-or-empty-input)).
2. Cast `ViewData.Model` to `MenuViewModelBase`; skip all menu work when the cast yields null ([BR-06](../business-rules.md#br-06-context-and-menu-decoration-require-the-matching-base-view-model)).
3. Resolve the menu from session: when `Session["BusinessOnlineMenu"]` is null, call `menuService.GetBusinessOnlineMenu(User.Identity.Name)` (delegates to [OP-12](op-12-retrieve-the-business-online-menu-for-a-user.md)), map through `Mappers.MapMenuViewModel` ([OP-13](op-13-map-the-menu-contract-to-view-models.md)), and cache the result in session; otherwise reuse the cached `MenuViewModel` ([BR-21](../business-rules.md#br-21-business-online-menu-is-cached-once-per-session)).
4. Set `model.Menu.CurrentApplicationName` from `Request.Url.ApplicationName()`.
5. Compute `model.Menu.CurrentItemId` through `GetCurrentItemId` ([BR-22](../business-rules.md#br-22-active-menu-item-identified-by-app-and-page-link-match)).
   - When the absolute path minus `/` equals the current application name, treat the page link as `Home/Index`; otherwise strip the `/{app}/` prefix from the absolute path.
   - When the resulting link contains no `/`, append `/Index`.
   - Split on `/`; when there are three or more segments keep only the first two — this drops route ids from the lookup key ([BR-24](../business-rules.md#br-24-route-identifiers-excluded-from-the-menu-lookup-key)).
   - Re-append the original query string.
   - Return the `PageId` of the first menu item whose `ApplicationName` matches the current application (case-insensitive) and whose `PageLink` matches the computed link (case-insensitive), or `""` when no match exists ([BR-25](../business-rules.md#br-25-root-request-maps-to-home%2Findex)).
6. Set `model.Menu.IsMenuExpanded = true` — the menu is always rendered expanded.
7. Set `model.Menu.MenuCategory` from the derived controller's abstract `MenuCategory` property.
8. Set `model.Menu.IsExternalUser` from `ApplicationUser.IsExternal`, where `ApplicationUser` lazily calls `UserProfileService.GetCurrentUser()` and memoizes it for the request ([BR-23](../business-rules.md#br-23-external%2Finternal-user-status-resolved-once-per-request)).
9. Call `base.OnActionExecuted(filterContext)`, which runs [OP-02](op-02-project-web-context-onto-the-view-model.md).

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([Action executed])
	Guard[Guard filterContext]
	Cast[Cast ViewData.Model to MenuViewModelBase]
	Skip([Skip menu work])
	Cache{Menu cached in session?}
	Fetch[Fetch and map menu]
	Reuse[Reuse cached menu]
	Item[Compute CurrentItemId]
	User[Resolve IsExternalUser]
	EndOk([Continue])
	Start --> Guard
	Guard --> Cast
	Cast -->|No match| Skip
	Cast -->|Match| Cache
	Cache -->|Miss| Fetch
	Cache -->|Hit| Reuse
	Fetch --> Item
	Reuse --> Item
	Item --> User
	User --> EndOk
	Skip --> EndOk
```

## Failure and edge-case behavior

- No unexpected failure paths beyond argument-guard exceptions and delegated dependency behavior were identified for this operation.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

## Sources
- `src/Web.Mvc/Controllers/MenuControllerBase.cs`
