Skip to main content

Sessions, Statics, and Multi-User Safety

Every static field and singleton of LegacyOrderDesk is found and classified (keep static vs move to session / profile store / browser storage), the five per-user statics of AppState become a typed UserSessionContext behind Application.Session, and the Orders screen is tested with two browser sessions: changing the filter in one does not affect the other. Sign out runs the one cleanup routine the lesson asks for.

Run it

cd "LearnWisej-Samples/From WinForms to the Web Course/Module 4/OrderDesk.Web"
dotnet run -f net10.0 --urls http://localhost:5604

Then open http://localhost:5604. (Visual Studio: open OrderDesk.slnx, F5.)

What to try

ActionWhat you should see
Page loadThe Orders card with all 5 orders and the Session card: User (not signed in), Active filter All
Sign in as kellyThe context becomes kelly · Acme · Northwind Traders · filter Open: the combos follow, the grid shows 2 of 5 orders (Northwind highlighted), the Session card shows the four values
Sign in as samsam · Globex · Fabrikam Inc · filter Invoiced: 1 of 5 orders
Filter / customer combosWrite to this session's context and re-filter the grid
Open second session ↗ → in the new tab Sign in as sam and change its filter → back in the first tab Re-read stateThe first tab still shows kelly's customer and filter: each session reads its own UserContext (steps in docs/TwoSessionTest.md)
Sign outSessionCleanup.Run deletes the session's temp folder and SessionContext.Reset() clears only this session's context; the other tab is untouched

Where things live

Module 4/
└─ OrderDesk.Web/ the Wisej.NET 4 app (net10.0-windows;net10.0), port 5604
├─ Program.cs / Startup.cs session entry point (Application.MainPage + the ApplicationExit cleanup) / Kestrel host
├─ Default.html / Default.json / Web.config
├─ Domain/ the reused business logic (Order, Customer, OrderService, CustomerService, InvoiceDocument, SampleData)
├─ Services/UserSessionContext.cs the typed context: plain data, no Wisej reference
├─ Services/SessionContext.cs Current (lazy, per browser session in Application.Session) + Reset()
├─ Services/SessionCleanup.cs the one routine logout and ApplicationExit share
├─ Services/StorageRoot.cs Web.config OrderDesk.StorageRoot (default App_Data)
├─ Views/Ui.cs colours + toast helper
├─ MainPage.cs / .Designer.cs the Orders screen + the Session card
├─ App_Data/ created at run time: tmp/<session>/report-job.txt
└─ docs/ the lab deliverables + migration-log.md

Runtime facts

  • Application.Session is a dynamic bag (also a Dictionary<string, object>): a member that was never set reads as null. SessionContext.Current wraps exactly that and creates the context lazily.
  • Application.ApplicationExit is a static event: subscribed once per session in Program.Main, it runs even after the page is disposed. It has no UI to push to — log to the host, do not touch controls.
  • Application.Navigate(Application.Url, "_blank") opens a second session in the same server process; Application.SessionCount counts them; Application.SessionId identifies this one.
  • Application.StartupPath is the project folder under dotnet run, so App_Data/tmp is created next to the sources; delete App_Data/ to reset the sample.
  • The projects multi-target net10.0-windows;net10.0, so dotnet run needs -f net10.0 (or -f net10.0-windows).