---
title: SAIF.Framework.Web.Mvc operations and processes
summary: Business and technical operations supported by this library.
status: draft
owner: SAIF Documentation
last_reviewed: 2026-09-17
library: SAIF.Framework.Web.Mvc
reference_type: package
---

# SAIF.Framework.Web.Mvc operations and processes

This page is the operation catalog and cross-operation hub for this library. Each operation's detailed, step-by-step logic lives in its own page under `operations/`.

## Operation catalog
| Operation | Intent | Trigger | Inputs | Outputs | Rules |
| --- | --- | --- | --- | --- | --- |
| [Resolve web context for an incoming request](operations/op-01-resolve-web-context.md) | Resolve and populate the request's web context before the action runs | MVC action-filter pipeline, before every action on a derived controller | `ActionExecutingContext` (request form, query string, referrer, session), `TempData` | `WebContext` protected property populated; `Context=` entry appended to the IIS log | [BR-01](business-rules.md#br-01-guarded-arguments-reject-null-or-empty-input), [BR-02](business-rules.md#br-02-tempdata-context-id-takes-precedence), [BR-03](business-rules.md#br-03-form-field-wins-over-query-string-for-context-id), [BR-04](business-rules.md#br-04-cross-application-arrival-inherits-the-referring-context), [BR-05](business-rules.md#br-05-request-supplied-context-value-always-overrides) |
| [Project web context onto the view model](operations/op-02-project-web-context-onto-the-view-model.md) | Copy the resolved web context onto the current view model after the action executes | MVC action-filter pipeline, after the action result is produced | `filterContext.Controller.ViewData.Model`, resolved `WebContext` | `WebContextViewModelBase.WebContext.ContextId` / `.ContextValue` populated | [BR-06](business-rules.md#br-06-context-and-menu-decoration-require-the-matching-base-view-model) |
| [Create a new web context](operations/op-03-create-a-new-web-context.md) | Create a brand-new web context via the remote WCF service and cache it in session | [BR-04](business-rules.md#br-04-cross-application-arrival-inherits-the-referring-context) cross-application arrival referenced by OP-01 step 6, or `Get(contextId)` on cache miss | Optional context id; `serviceUrl` from session key `ContextServiceUrl` | `IWebContext`; session cache updated | [BR-09](business-rules.md#br-09-every-resolved-context-is-cached-by-id) |
| [Get a web context by id (session-cache first)](operations/op-04-get-web-context-by-id.md) | Return a cached web context by id, recreating it remotely on a cache miss | OP-01 (resolve web context) step 4 | `contextId` | `IWebContext` | [BR-01](business-rules.md#br-01-guarded-arguments-reject-null-or-empty-input), [BR-10](business-rules.md#br-10-context-lookup-is-session-cache-first) |
| [Get a web context by application and session](operations/op-05-get-web-context-by-application-and-session.md) | Retrieve the context associated with a referring application and session, always from the remote service | OP-01 (resolve web context) step 5 (cross-application arrival) | `applicationName`, `sessionId` | `IWebContext` | [BR-01](business-rules.md#br-01-guarded-arguments-reject-null-or-empty-input), [BR-09](business-rules.md#br-09-every-resolved-context-is-cached-by-id) |
| [Save a web context remotely](operations/op-06-save-a-web-context-remotely.md) | Persist a web context to the remote WCF service on cross-application navigation | OP-07 (navigate between applications and views) step 3 (cross-application navigation) | `applicationName`, `sessionId`, `context` | Remote persistence; no return value | [BR-01](business-rules.md#br-01-guarded-arguments-reject-null-or-empty-input) |
| [Navigate between applications and views](operations/op-07-navigate-between-applications-and-views.md) | Redirect the user to a target URL, handing off web context across or within applications | POST from a view's navigation control | `NavigateViewModel.Url`; `Request.UrlReferrer`; `Session.SessionID`; resolved `WebContext` | `RedirectResult` to `model.Url`, or `null` when `model.Url` is null | [BR-01](business-rules.md#br-01-guarded-arguments-reject-null-or-empty-input), [BR-07](business-rules.md#br-07-navigation-target-and-source-application-derivation), [BR-08](business-rules.md#br-08-cross-application-navigation-hands-context-over-via-the-remote-service) |
| [Handle and log an unhandled action exception](operations/op-08-handle-and-log-an-unhandled-action-exception.md) | Log an unhandled action exception with full diagnostic context and redirect non-AJAX requests | Any unhandled exception in an action on a controller the filter is applied to | `ExceptionContext` (request, controller, exception) | Log entry via `ILogService`; redirect for non-AJAX requests | [BR-11](business-rules.md#br-11-exception-handling-requires-the-log-service-and-filter-context), [BR-12](business-rules.md#br-12-logged-exception-state-includes-full-context-and-request-diagnostics), [BR-13](business-rules.md#br-13-logging-failures-never-surface-to-the-user), [BR-14](business-rules.md#br-14-ajax-requests-are-logged-but-not-redirected) |
| [Authorize a request against SAIF roles](operations/op-09-authorize-a-request-against-saif-roles.md) | Decide whether the current user is authorized for any of the roles declared on the filter | MVC authorization filter stage on any controller/action decorated with `SaifAuthorizeAttribute` (applied as `[SaifAuthorize]`) | `HttpContextBase`; `Roles` (comma-joined from the constructor); `_ForceProductionRole`; injected `IUserProfileService` and `IEnvironmentService` | `bool` authorization decision | [BR-01](business-rules.md#br-01-guarded-arguments-reject-null-or-empty-input), [BR-15](business-rules.md#br-15-authorization-filter-requires-its-injected-services), [BR-16](business-rules.md#br-16-no-roles-declared-authorizes-everyone), [BR-17](business-rules.md#br-17-no-resolvable-system-user-is-denied), [BR-18](business-rules.md#br-18-access-granted-on-any-satisfied-role) |
| [Handle an unauthorized request](operations/op-10-handle-an-unauthorized-request.md) | Log a denied authorization attempt and redirect the user to the error page | `AuthorizeCore` returned `false` | `AuthorizationContext`; injected `ILogService` and `IEnvironmentService` | Logged `SecurityException`; `RedirectResult` to the error page | [BR-01](business-rules.md#br-01-guarded-arguments-reject-null-or-empty-input), [BR-15](business-rules.md#br-15-authorization-filter-requires-its-injected-services), [BR-19](business-rules.md#br-19-authorization-denials-are-logged-as-a-security-exception), [BR-20](business-rules.md#br-20-denied-users-are-redirected-to-the-standard-error-page) |
| [Build and attach the Business Online menu](operations/op-11-build-and-attach-the-business-online-menu.md) | Populate the current view model's menu, decorating it with the active item, category, and user status | After every action on a controller derived from `MenuControllerBase` | `ViewData.Model`, `User.Identity.Name`, request URL, `HttpContext.Session["BusinessOnlineMenu"]` | `MenuViewModelBase.Menu` fully populated | [BR-01](business-rules.md#br-01-guarded-arguments-reject-null-or-empty-input), [BR-06](business-rules.md#br-06-context-and-menu-decoration-require-the-matching-base-view-model), [BR-21](business-rules.md#br-21-business-online-menu-is-cached-once-per-session), [BR-22](business-rules.md#br-22-active-menu-item-identified-by-app-and-page-link-match), [BR-23](business-rules.md#br-23-external%2Finternal-user-status-resolved-once-per-request), [BR-24](business-rules.md#br-24-route-identifiers-excluded-from-the-menu-lookup-key), [BR-25](business-rules.md#br-25-root-request-maps-to-home%2Findex) |
| [Retrieve the Business Online menu for a user](operations/op-12-retrieve-the-business-online-menu-for-a-user.md) | Query the Oracle-backed menu repository for a user's visible menu items and favorites | OP-11 (build and attach the Business Online menu) step 3 (session cache miss) | `mailId`, typically `DOMAIN\user` from `User.Identity.Name` | `BusinessOnlineMenu` with `Favorites` and `Items` arrays | [BR-01](business-rules.md#br-01-guarded-arguments-reject-null-or-empty-input), [BR-26](business-rules.md#br-26-domain-qualified-mail-id-reduced-before-lookup), [BR-27](business-rules.md#br-27-every-user-also-receives-the-shared-unsecured-menu), [BR-28](business-rules.md#br-28-only-visible-menu-rows-are-returned), [BR-29](business-rules.md#br-29-menu-rows-are-ordered-by-sort-order), [BR-30](business-rules.md#br-30-favorite-flag-partitions-rows-into-favorites-and-items) |
| [Map the menu contract to view models](operations/op-13-map-the-menu-contract-to-view-models.md) | Project the menu contract object onto MVC view models for rendering | OP-11 (build and attach the Business Online menu) step 3 | `BusinessOnlineMenu` | `MenuViewModel` with `Favorites` and `Items` | — |
| [Register common web dependencies](operations/op-14-register-common-web-dependencies.md) | Wire MVC/Web API discovery, NHibernate unit-of-work factories, and menu/web-context/environment services into the consumer's Autofac container | Consuming application startup composition* | `ContainerBuilder`, a type from the application assembly, optional extra NHibernate class-map assemblies | Registrations added to the container; the caller still owns `Build()` | [BR-01](business-rules.md#br-01-guarded-arguments-reject-null-or-empty-input), [BR-31](business-rules.md#br-31-menu-data-is-read-from-the-oracle-menu-schema) |
| [Initialize the web context service for a session](operations/op-15-initialize-the-web-context-service-for-a-session.md) | Set up the session-backed context dictionary and cached endpoint URL on first resolution in a session | Autofac `InstancePerRequest` resolution of `IWebContextService` | `IEnvironmentService` | Session-backed context dictionary and cached service URL | [BR-32](business-rules.md#br-32-web-context-repository-created-once-per-session), [BR-33](business-rules.md#br-33-context-service-endpoint-resolved-once-per-session) |
| [Project model-state errors into view models](operations/op-16-project-model-state-errors-into-view-models.md) | Translate ASP.NET model-state validation errors into JSON-friendly, grid-row-correlated view models | Controller action returning validation results, typically as JSON | `ModelStateDictionary`, optional grid property and row-id expressions | `ErrorViewModel[]` | [BR-34](business-rules.md#br-34-pending-change-grid-keys-are-not-correlated-to-a-row), [BR-35](business-rules.md#br-35-grid-error-key-normalized-before-the-row-id-is-read), [BR-36](business-rules.md#br-36-error-keys-are-dom-safe) |
| [Collect user messages through ModelStateWrapper](operations/op-17-collect-user-messages-through-modelstatewrapper.md) | Record error, warning, and informational messages while de-duplicating repeated text | Domain or service code writing messages through `IMessageContainer` | Property name and message text | Populated `ModelStateDictionary`, `Warnings`, `Informationals` | [BR-37](business-rules.md#br-37-duplicate-error-message-displayed-once-but-still-flags-the-field), [BR-38](business-rules.md#br-38-duplicate-warnings-and-informational-messages-are-suppressed) |
| [Bind a JSON date value](operations/op-18-bind-a-json-date-value.md) | Bind a request value to a `DateTime`, tolerating missing or unparseable input | MVC model binding for a bound `DateTime` when the binder is registered | `bindingContext.ValueProvider` value for `ModelName` | `DateTime`, or the raw null value | [BR-39](business-rules.md#br-39-missing-date-value-binds-to-datetime-default), [BR-40](business-rules.md#br-40-asp.net-json-date-form-is-converted-from-unix-epoch), [BR-41](business-rules.md#br-41-unparseable-date-binds-to-the-datetime-default) |
| [Render the Business Online menu](operations/op-19-render-the-business-online-menu.md) | Emit the favorites and category-grouped navigation menu markup for the current view | Razor view calling the helper | `HtmlHelper`, `MenuViewModel`, `WebContextViewModel` | Markup written to `helper.ViewContext.Writer`; the "old school" variants return an `HtmlString` instead | [BR-01](business-rules.md#br-01-guarded-arguments-reject-null-or-empty-input), [BR-42](business-rules.md#br-42-favorite-display-text-falls-back-to-page-name), [BR-43](business-rules.md#br-43-menu-link-title-attribute-is-conditional), [BR-44](business-rules.md#br-44-menu-items-ordered-by-category-and-grouped), [BR-45](business-rules.md#br-45-top-menu-shows-only-the-controller's-declared-category) |
| [Render the web context control](operations/op-20-render-the-web-context-control.md) | Emit the hidden/visible web-context form used to round-trip context id and value | Razor view calling the helper | `WebContextViewModel` | `<form id="frmWebContext">` markup written to the view writer | [BR-01](business-rules.md#br-01-guarded-arguments-reject-null-or-empty-input), [BR-46](business-rules.md#br-46-web-context-control-hidden-unless-explicitly-enabled) |
| [Render a linked (chained) dropdown](operations/op-21-render-a-linked-chained-dropdown.md) | Emit a `<select>` whose visible options are filtered client-side by a parent field's value | Razor view calling the helper | Field name or lambda expression, parent field id, `IEnumerable<LinkedSelectListItem>`, `removeDefault`, html attributes | `MvcHtmlString` `<select>` markup | [BR-47](business-rules.md#br-47-generated-element-ids-sanitize-dots-to-underscores), [BR-48](business-rules.md#br-48-caller-html-attributes-merge-by-concatenation), [BR-49](business-rules.md#br-49-linked-dropdown-option-carries-parent-value-as-css-class), [BR-50](business-rules.md#br-50-default-option-suppressed-when-requested), [BR-51](business-rules.md#br-51-selected-value-matching-is-case-insensitive) |
| [Render a character-counting textarea](operations/op-22-render-a-character-counting-textarea.md) | Emit a labeled textarea with client-side character-count data attributes | Razor view calling the helper | Field name or lambda, optional label text, html attributes, `startLength` (default 0), `maxLength` (default 4000) | `MvcHtmlString` — label or span markup followed by the `<textarea>` | [BR-47](business-rules.md#br-47-generated-element-ids-sanitize-dots-to-underscores), [BR-52](business-rules.md#br-52-strongly-typed-textarea-counter-always-uses-the-4000-default), [BR-53](business-rules.md#br-53-textarea-counter-without-label-text-renders-a-bare-span) |
| [Build a toolbar through the fluent API](operations/op-23-build-a-toolbar-through-the-fluent-api.md) | Configure a server-rendered toolbar component through a fluent builder chain | Razor view calling `Html.SAIF().Toolbar()` | Fluent configuration lambda | A configured `Toolbar` whose `Render()` and `ToHtmlString()` currently emit no markup | [BR-54](business-rules.md#br-54-standard-save-button-uses-a-fixed-id%2C-icon%2C-and-tooltip) |
| [Determine Glimpse diagnostic access](operations/op-24-determine-glimpse-diagnostic-access.md) | Decide whether the current request should be granted access to the Glimpse diagnostics panel | Caller checking whether the Glimpse diagnostics panel should be shown* | `HttpContextBase` — `Server.MachineName` and `User` | `bool` | [BR-55](business-rules.md#br-55-non-production-servers-use-the-test-glimpse-resource-variant), [BR-56](business-rules.md#br-56-glimpse-access-requires-an-authenticated-user-and-a-negated-role-test) |
| [Register style bundles](operations/op-25-register-style-bundles.md) | Build and register the common and Kendo style bundles the consuming application serves | Consuming application's bundle registration at startup* | `BundleCollection`, virtual path, Kendo version string | `StyleBundle` added to the collection and returned | [BR-57](business-rules.md#br-57-common-style-bundle-always-includes-the-toolbar-stylesheet), [BR-58](business-rules.md#br-58-kendo-styles-are-version-scoped-and-always-include-common%2Fdefault), [BR-59](business-rules.md#br-59-bundle-file-names-get-.css-appended-automatically) |
| [Render a label with custom attributes](operations/op-26-render-a-label-with-custom-attributes.md) | Resolve and render a `<label>` element's text using a defined precedence order | Razor view calling the helper | Lambda expression, optional label text, html attributes | `MvcHtmlString` | [BR-60](business-rules.md#br-60-label-text-precedence-order), [BR-61](business-rules.md#br-61-label-with-no-resolvable-text-renders-nothing) |
| [Seed a default context value on cross-application arrival](operations/op-27-seed-a-default-context-value-on-cross-application-arrival.md) | Set an initial context value when the user arrives from a different application | Consuming application calling the helper after context resolution* | Request referrer and URL, candidate values | `context.CurrentValue` possibly set | [BR-62](business-rules.md#br-62-default-context-value-only-seeded-when-a-referrer-exists), [BR-63](business-rules.md#br-63-default-context-value-seeded-from-the-first-non-empty-candidate) |
| [Clear grid pending-change collections](operations/op-28-clear-grid-pending-change-collections.md) | Reset a grid's pending add/delete/update collections after a successful save while preserving displayed rows | Controller resetting a grid after a successful save* | `GridViewModel<T>` | `Added`, `Deleted`, and `Updated` replaced with empty lists | [BR-64](business-rules.md#br-64-clearing-a-grid-resets-only-pending-change-collections) |

## Process flow diagram
The following diagram visualizes the primary operational flow across the core request-handling operations.

```mermaid
flowchart TD
	Req([Incoming request]) --> Ctx[OP-01 Resolve web context]
	Ctx --> Auth{SaifAuthorize applied?}
	Auth -->|Yes, denied| OP10[OP-10 Handle unauthorized request]
	Auth -->|Yes, allowed| Action[Controller action executes]
	Auth -->|Not applied| Action
	Action -->|Unhandled exception| OP08[OP-08 Handle and log exception]
	Action --> OP02[OP-02 Project context onto view model]
	OP02 --> OP11[OP-11 Build and attach menu]
	OP11 --> Render["Razor view renders menu, context, toolbar"]
	Render --> Resp([Response returned])
	OP10 --> Resp
	OP08 --> Resp
```

## Failure and edge-case behavior
- A null `filterContext`/`model`/service argument anywhere in this library throws immediately from `Enforce` rather than failing silently ([BR-01](business-rules.md#br-01-guarded-arguments-reject-null-or-empty-input)).
- Unhandled action exceptions are always routed through [OP-08](operations/op-08-handle-and-log-an-unhandled-action-exception.md), which never itself throws even when logging fails.
- Authorization denial is always routed through [OP-10](operations/op-10-handle-an-unauthorized-request.md), which logs and redirects rather than returning an HTTP status code directly.
- Menu and web-context decoration ([OP-02](operations/op-02-project-web-context-onto-the-view-model.md), [OP-11](operations/op-11-build-and-attach-the-business-online-menu.md)) silently no-op when the current view model does not derive from the expected base type.

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Business rules](business-rules.md)
- [Security and authorization](security-authorization.md)
- [API reference](api/index.md)

## Sources
- `src/Web.Mvc/ActionFilters/HandleExceptionAttribute.cs`
- `src/Web.Mvc/ActionFilters/SaifAuthorizeAttribute.cs`
- `src/Web.Mvc/Classes/Mappers.cs`
- `src/Web.Mvc/Classes/MenuService.cs`
- `src/Web.Mvc/Classes/ModelStateWrapper.cs`
- `src/Web.Mvc/Controllers/MenuControllerBase.cs`
- `src/Web.Mvc/Controllers/WebContextControllerBase.cs`
- `src/Web.Mvc/Extensions/AutofacExtensions.cs`
- `src/Web.Mvc/Extensions/BundleTableExtensions.cs`
- `src/Web.Mvc/Extensions/LabelExtensions.cs`
- `src/Web.Mvc/Extensions/MenuExtensions.cs`
- `src/Web.Mvc/Extensions/ModelStateExtensions.cs`
- `src/Web.Mvc/Extensions/WebContextExtensions.cs`
- `src/Web.Mvc/ModelBinders/JsonDateTimeModelBinder.cs`
- `src/Web.Mvc/UI/Extensions/HtmlHelperExtensions.cs`
- `src/Web.Mvc/UI/Extensions/LinkedDropdownHelper.cs`
- `src/Web.Mvc/UI/Extensions/TextCounterHelper.cs`
- `src/Web.Mvc/UI/Toolbar/*.cs`
- `src/Web.Mvc/UI/ViewComponentFactory.cs`
- `src/Web.Mvc/ViewModels/GridRowViewModel.cs`
- `src/Web/Extensions/HttpContextExtensions.cs`
- `src/Web/WebContextService.cs`
- `src/Web/WebContextServiceClient.cs`
