Transports overview¶
A transport is the wire-level protocol your clients use to talk to the OpStream server. Three are first-class:
| Transport | Best for | Package |
|---|---|---|
| SignalR | Web / Blazor / .NET clients, easy reconnection, fallbacks | OpStream.Server.Transports.SignalR |
| WebSockets | Raw-WS clients (mobile, native, custom protocols) | OpStream.Server.Transports.WebSockets |
| gRPC | Service-to-service, polyglot clients, streaming | OpStream.Server.Transports.gRPC |
All three sit on top of the same DocumentRouter — they're just different
serializations of the same operations: JoinDocument, SendOp, and
UpdateAwareness in / ReceiveOp, ReceiveAwareness,
PeerDisconnected out.
Picking one¶
- Browser or Blazor client → SignalR is the path of
least resistance: built-in reconnection, fallback to long-polling on
hostile networks, dead-simple
services.AddSignalR()integration. - Mobile / native client → WebSockets keeps the protocol lean and avoids the SignalR client-side runtime.
- Service mesh / polyglot → gRPC for bidirectional streaming with strong typing across languages.
You can register more than one transport in the same app:
services.AddOpStream()
.UseSqlServer(connStr)
.AddSignalRTransport() // /opstream/signalr
.AddWebSocketTransport() // /opstream/ws
.AddGrpcTransport(); // /OpStream.Server.Transports.gRPC.OpStreamService
Each transport exposes its own endpoint; the router and storage are shared.
Endpoint mapping¶
Every transport's package also ships an Map* extension on
IEndpointRouteBuilder:
Override the path with the optional argument; see each transport page.
Wire compatibility across transports¶
The op payload on the wire is the engine-specific JSON — the same
shape produced by JsonSerializer.SerializeToUtf8Bytes(op,
OpStreamJsonOptions.Default). A client that knows the engine can talk
to any of the three transports interchangeably.
See Wire protocol.