Skip to content

Commit ee390ce

Browse files
committed
Sessions: what they are for and their rough edges
1 parent 9631b59 commit ee390ce

1 file changed

Lines changed: 24 additions & 0 deletions

File tree

‎README.md‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,30 @@ Handler.DestroySession("client-42");
424424

425425
Sessions are stored in a process-wide registry. Binding (`ServiceBinder.BindService`, `BindMethod`, `BindInterface`, a `JsonRpcService` constructor), the per-session `Config` setters and `Handler.GetSessionHandler(sessionId)` create a session; it remains until `Handler.DestroySession(sessionId)` is called. A request for a session id that was never registered creates nothing: every call in it answers `-32601` and the default session's methods are not reachable through it, so an id taken from a route or header cannot grow the registry. Each registration or destruction makes every thread refresh its copy of the registry on its next lookup, so register at startup or when a connection or tenant appears, not per request, and destroy tenant- or connection-scoped sessions when their lifetime ends.
426426

427+
### What sessions are for
428+
429+
A session is an independent method table with its own serializer, `jsonrpc` version policy and handlers, chosen per request by its id. That covers:
430+
431+
- **API versions.** Bind `v1` and `v2` as two sessions with different method names or parameter contracts and serve both at once.
432+
- **Tenants.** Bind the same class once per tenant, each session over its own instance, and give some tenants methods the others do not have.
433+
- **Connections.** Bind a session when a client connects and destroy it when the client disconnects, so its methods live exactly as long as the connection.
434+
- **Capability sets.** Offer a small public session and a larger administrative one instead of a mode flag inside every method.
435+
- **Migration and experiments.** Route selected clients to a session bound to a new implementation of the same method names while the rest keep the established one.
436+
- **Wire compatibility.** Set the serializer, version policy and error handlers per session for clients with different expectations.
437+
- **Several surfaces in one process.** An embedded host runs independent method sets side by side, even over one transport: the Kestrel HTTP endpoint picks the session per request through `JsonRpcOptions.SessionSelector`.
438+
439+
### Rough edges
440+
441+
- **Authorisation.** A session id is routing, not a permission. When it selects tenant data or privileged methods, the host decides which id a caller may name; the library guarantees only that an unknown id reaches nothing.
442+
- **Lifetime.** A session stays in the registry until `Handler.DestroySession(sessionId)`. Connection- and tenant-scoped sessions need cleanup the host can rely on, such as a disconnect callback.
443+
- **Registration cost.** Each registration or destruction makes every thread refresh its view of the registry on its next lookup, so a session per request is the wrong shape; a session per connection or tenant is fine.
444+
- **Shared instances.** `BindService(sessionId, instance)` hands the same object to every concurrent call, so it must be thread-safe and must not keep request state in fields. `BindService(sessionId, typeof(T), resolve)` and `AddJsonRpcService<T>(ServiceLifetime.Scoped)` give each call its own instance; see [Classes](#classes).
445+
- **The default session.** A `JsonRpcService` subclass built with the parameterless constructor binds to the default session, and a handler setter on `Config` without a session id changes the default session's handler.
446+
- **Compatibility.** Two versions can expose different signatures, but an old result shape or old semantics still needs its own implementation or an adapter.
447+
- **Configuration scope.** A session is not a whole server: exception disclosure is process-wide and the serializer can also be chosen per call; the scopes are listed under [Configuration](#configuration).
448+
449+
### Context
450+
427451
Pass an arbitrary context object through to your methods and read it with `Handler.RpcContext()` or `JsonRpcContext.Current().Value` (the AspNetCore package passes the `HttpContext` or `ConnectionContext`):
428452

429453
```csharp

0 commit comments

Comments
 (0)