Skip to main content

Who Owns the UI

This example is the Session Inspector + Lifecycle Logger of TicketOps Live. A diagnostics group box (diagnosticsGroupBox) shows the current time, the client id, the session id, the browser, the server thread serving the current event and a per-session counter kept in Application.Session; a lifecycle log (lifecycleListBox) records load, the counter, the background update, other sessions joining and leaving (through a global SessionRegistry), the session timeout and the exit.

Run it

cd "LearnWisej-Samples/Real-Time Server Push Course/Module 2/TicketOpsLive"
dotnet run -f net10.0 --urls http://localhost:5302

Then open http://localhost:5302, and open it a second time (or click Open second window).

What to try

ControlWhat you should see
Counter +1counterLabel grows; a second tab keeps its own value
Background update~1.5 s later "Background update at …" appears in the log with no click in between; the server thread id changes
Open second windowa second tab: same client id (it identifies the browser), its own session id and counter; both logs show Session xxxxxxxx joined
Clear logempties the lifecycle log
Close or refresh the other tabonce its session ends, this tab logs Session xxxxxxxx left without anyone clicking here

Server thread. threadLabel is refreshed on every event: the id moves because the server thread is a pool thread reused for whichever session sends the next event. Out-of-bound code needs the context, not the thread.

After a refresh (F5), and after the session ends

What you look atAfter F5Why
counterLabel (Application.Session.Counter)back to 0the bag belonged to the session that ended
lifecycle logemptycontrol state of a page that no longer exists
clientIdLabel / sessionIdLabelsame client id, new session ida new session in the same browser
liveSessionsLabelthe old id leaves, the new one joinsthe global registry outlives sessions

When a session ends (Application.Exit() or the timeout), ApplicationExit logs TicketOps session exited: <ClientId> to the server console and Cleanup() unsubscribes SessionsChanged, unregisters the session and detaches ApplicationExit/SessionTimeout — once, even though Disposed calls it too. About two minutes before the idle timeout, Application.SessionTimeout logs "Session is about to time out" and Wisej.NET shows its "prolong the session?" dialog.

Polling fallback. Add "enableWebSocket": false to Default.json and restart: the background update still arrives (about a second late) because polling is requested while the task runs.