Session, State, Tenant & Concurrency Design
A tenant-aware SessionContext that owns who the
user is and which customer they are working in, a CommandContext with a correlation id on every command, a
TenantGuard in every service, optimistic concurrency on work orders, and the ConflictDialog that explains a
stale edit and offers Reload · Compare · Cancel.
Nothing here is deployed anywhere; it is a plain Wisej.NET 4 project that runs on your machine, with in-memory data.
Run it
cd "LearnWisej-Samples/Enterprise Wisej.NET Course\Module 3\EnterpriseOps"
dotnet run -f net10.0 --urls http://localhost:5203
Then open http://localhost:5203. (Visual Studio: open EnterpriseOps.slnx, press F5 — the port is in
Properties/launchSettings.json.)
What to click
The screen: the header with cboTenant (only the tenants the signed-in user's claims entitle them to), the work
queue for the current tenant (dgvWorkQueue, with a Version column), Open selected in editor, the editor
(txtTitle, cboStatus, read-only txtVersion, Save), a banner for validation and errors, and the dark
footer lblStatusBar.
| Control | Path | What you should see |
|---|---|---|
| Open selected in editor | success | txtVersion shows the token the record was loaded at, e.g. v7; footer Editing — expected version v7 |
| Save | success | footer Saved — v7 → v8 · correlation …; the queue's Version column moves |
| Save (empty title) | validation | amber banner "A work order needs a title." — the service rejected it, nothing written |
| Save (after another tab saved) | failure + recovery | footer Save rejected — expected v7, found v8 · correlation …, then the conflict dialog |
cboTenant → another tenant | success | the editor is dropped; the queue reloads with a different set of rows |
In the conflict dialog: Reload latest (discard your edits, take the current record), Compare changes (field by field — the dialog stays open), Cancel (nothing saved, nothing lost, your edit stays on screen).
Reproduce the failure path
Open http://localhost:5203 in two browser tabs — two sessions, two SessionContext objects, one store.
- in both tabs select 2002 · Repair loading dock pump, click Open selected in editor —
v7; - tab 1: change the status, click Save — the store moves to
v8; - tab 2: change the title to Repair loading dock pump — urgent, click Save — rejected, and the conflict dialog explains why;
- click Compare changes — Title, Status and Version differ;
- click Reload latest — the editor rebinds at
v8, and the correlation ids tie every step to the audit log.
Where things live
Module 3/
└─ EnterpriseOps/
├─ UI/ WorkOrderEditorPage (queue + editor), ConflictDialog (Reload · Compare · Cancel)
├─ Domain/ WorkOrder (+ Version), ConcurrencyToken, Tenant, WorkOrderStatus, WorkQueueRow
├─ Services/ WorkOrderService, ConflictResolutionService, ConflictInfo, SaveWorkOrderCommand/Result,
│ WorkOrderEditModel, TenantDirectory, ServiceRegistry (per-session, no .Current)
├─ Security/ SessionContext, CommandContext, TenantGuard, AuditTrail, SharedStateAttribute,
│ IdentityProvider, VerifiedIdentity
├─ Data/ WorkOrderStore (shared, locked, clones on read), SeedData (2002 = the record)
├─ Diagnostics/ ActivityTrace (server log via System.Diagnostics.Trace), ErrorLog
├─ Resources/ UiText
└─ docs/ the five deliverables + the state ownership map