Background Tasks, Real-Time Updates & Sync
A 600-row CSV of tickets (with four deliberately bad
rows) is imported on a background task started with Application.StartTask, progress and a log panel
are pushed to the browser with Application.Update(this, () => …) at a bounded rate, ⏹ Cancel stops
the run cooperatively between two rows and lets you resume, and every field the two threads share is
guarded by one lock. The screen never freezes — ↻ Refresh list works while the import runs.
Nothing here is deployed anywhere; it is a plain Wisej.NET 4 project that runs on your machine.
Run it
cd "LearnWisej-Samples/Production Architecture Deep Dive\Module 7\TicketOps"
dotnet run -f net10.0 --urls http://localhost:5107
Then open http://localhost:5107. (Visual Studio: open TicketOps.slnx, press F5 — the port is in
Properties/launchSettings.json.)
Requirements: .NET 10 SDK, the Wisej-4 4.1.0 NuGet package.
To see the polling fallback, set "enableWebSocket": false in Default.json and restart: the pushes
arrive about a second late, carried by Application.StartPolling(1000) / EndPolling().
What to try in the Ticket Import window
| Action | Path | What you should see |
|---|---|---|
| ▶ Start import | success + progress | the bar and n of 600 rows · imported · skipped advance; the import log gets Row 60 imported — 10% lines and four ⚠ Row … skipped — … lines (58 title, 214 due date, 287 assignee, 412 duplicate id). Ends with ✔ Import complete — 596 imported · 4 skipped. and 602 tickets in the repository |
| ↻ Refresh list (during the run) | UI stays responsive | the count grows, the import log gets ✔ List refreshed — 237 tickets; the bar never stops |
| ⏹ Cancel (during the run) | cancellation | amber banner Import cancelled. The rows already imported were kept; resume to continue.; Start now reads ▶ Resume import (row 349); click it to finish the file |
If the data store fails mid-import, the run stops cleanly before the failing row, the details go to the log, the user sees The import stopped because the data store is unavailable. Recover it, then resume. and Start offers ▶ Resume import (row n). A second start while a run is active is refused under the lock.
Where things live
TicketOps/
├─ Views/ImportPage the screen: launcher, progress marshaling, cancellation, BeginPush/EndPush
├─ Controls/StatusBanner reusable "● state" + banner UserControl (display only)
├─ Services/ IImportService / ImportService (the import logic, no Wisej types), ITicketService / TicketService
├─ Domain/ Ticket, TicketImportRules (pure functions), ImportModels, OperationResult
├─ Data/
│ ├─ ITicketRepository.cs persistence contract (InsertAsync is an atomic check-and-add)
│ ├─ InMemoryTicketRepository.cs lock-guarded fake store
│ └─ sample-tickets.csv 600 rows, ids 7001–7600, bad rows 58 / 214 / 287 / 412 (copied to the output folder)
├─ Infrastructure/ ILog / ActivityLog (server console), ImportFileLocator, AppComposition
├─ Resources/Strings.cs safe user-facing messages (ImportCancelled, ImportInterrupted, …)
├─ docs/ BackgroundTaskNotes.md · ImportRunbook.md
├─ Program.cs Wisej.NET session entry point → AppComposition
└─ Startup.cs Kestrel host (app.UseWisej())