Workflow UX: Wizards, Modal Orchestration & Compensation
The Escalation Wizard — six steps (Reason · Attachments · Approver · Due date ·
Notifications · Review) opened modally with ShowDialogAsync — fills one typed EscalationCommand, and
EscalationWorkflow : IEscalationWorkflow executes the whole transition
(validate → authorize → persist → notify → audit) and returns one typed WorkflowResult.
The failure path is: the notification fails after the persist succeeded. The escalation is
kept, a compensation is recorded in the manual-review queue, the audit entry explains the gap, and the queued
entry can be retried later. The simulated failure lives in FakeNotificationGateway: its SMTP relay times out on
the first e-mail of the session and delivers every send after that.
Nothing here is deployed anywhere; it is a plain Wisej.NET 4 project that runs on your machine, with in-memory data only.
Run it
cd "LearnWisej-Samples/Enterprise Wisej.NET Course\Module 7\EnterpriseOps"
dotnet run -f net10.0 --urls http://localhost:5207
Then open http://localhost:5207. (Visual Studio: open EnterpriseOps.slnx, press F5 — the port is in
Properties/launchSettings.json.)
Requirements: .NET 10 SDK, the Wisej-4 4.1.0 NuGet package.
dotnet build -nologo -v q passes for both target frameworks with 0 warnings and 0 errors.
What's on screen
- Work queue (
WorkQueuePage): header title, the queue grid (dgvWorkQueue), Escalate work order… (btnEscalate), a message banner (lblBanner), and the manual-review queue (lstCompensation) with Retry notification (btnRetryNotification). - Escalation Wizard (
EscalationWizard, modal): the steps rail (stepsRail), one panel per step,lblValidation, Cancel / Back / Next (Next becomes Finish on Review, Close after it), and the dark status strip (lblWizardStatus) under the wizard.
What to click
| Action | Path | What you should see |
|---|---|---|
| Select WO-100232 (Critical) → Escalate work order… → six steps → Finish (first e-mail of the session) | failure + compensation | amber banner "Escalation created — approver NOT notified.", persist ✓ · notify ✕ · CompensationAction: manual-review queued (#1), the WorkflowResult line in the status strip; after Close the row is Escalated and the manual-review queue has an open entry. The escalation is kept. |
| Select the open entry → Retry notification | recovery | the notification is re-sent, the entry is resolved, escalation.notify.retried is audited under a new correlation id |
| Escalate another work order → Finish | success | green banner "Escalation created and approver notified." |
| Next with an empty reason | validation | stays on step 1: "Reason: a reason is required", nothing persisted |
| Critical row, Next on step 2 with no file | validation | "a Critical escalation needs at least one attachment" |
ben.tech as approver → Next | validation (security) | "ben.tech is a Technician — only Supervisors and Managers approve" |
ana.ops as approver → Finish | validation at the command | EscalateAsync returns ValidationFailed ("you cannot approve your own escalation") and the wizard jumps back to step 3 because result.FirstFailingStep said so |
| Cancel → Yes, then Escalate… again | resume | the wizard reopens on the same step with every answer; the status strip says Draft resumed |
| Cancel → No | cancel | draft removed, staged uploads cleaned up; nothing was persisted |
Where things live
Module 7/
├─ EnterpriseOps.slnx
└─ EnterpriseOps/
├─ UI/
│ ├─ WorkQueuePage.cs / .Designer.cs the queue + the manual-review queue
│ └─ EscalationWizard.cs / .Designer.cs the modal wizard: stepsRail + six panels + Cancel/Back/Next
├─ Services/
│ ├─ SessionServices.cs per-session composition root (page + wizard share it)
│ ├─ SessionContext.cs ActivityTrace.cs (server log) WorkQueueRow.cs
│ └─ Workflow/ IEscalationWorkflow, EscalationWorkflow, EscalationCommand,
│ WorkflowResult, EscalationWizardState, WorkflowStateStore,
│ CompensationLog, WizardStep, StepValidation, WorkflowProgressObserver
├─ Domain/ WorkOrder.cs, Escalation.cs (+ Attachment, Approver, NotificationChannels)
├─ Data/ InMemoryWorkOrderStore, InMemoryEscalationStore, AttachmentStaging, SeedData (48 rows)
├─ Security/ UserRole.cs, PermissionService.cs, AuditLog.cs
├─ Integrations/ INotificationGateway + Fake (SMTP timeout on the first e-mail), IApproverDirectory + Fake
├─ docs/ the five deliverables + the SVG + the production-readiness note
├─ Program.cs Application.MainPage = new UI.WorkQueuePage()
└─ Startup.cs Kestrel host (app.UseWisej())