97 lines
4.9 KiB
Markdown
97 lines
4.9 KiB
Markdown
# SignalR — Known Issues & Limitations
|
|
|
|
## Protocol
|
|
|
|
### PROTO-1: Server-side IsRawBytesData pre-serialize
|
|
|
|
**Status:** Planned removal
|
|
**Affects:** `AcWebSignalRHubBase.SendMessageToClient`
|
|
|
|
The server forwards the client's `IsRawBytesData` flag in the response `SignalParams`. This causes the protocol to return raw `byte[]` instead of deserializing. The original design pre-serialized on the server side, but with the zero-copy typed deserialization path (`SignalDataType`), this is redundant.
|
|
|
|
**Plan:** Remove `IsRawBytesData` forwarding from server response path. The client should use `SignalDataType` for typed deserialization and explicit `byte[]` type for raw data.
|
|
|
|
### PROTO-2: Parameter serialization is per-parameter
|
|
|
|
**Status:** Known performance concern
|
|
**Affects:** `SignalParams.SetParameterValues` / `GetParameterValues`
|
|
|
|
Each parameter is individually serialized via `ToBinary()` / `BinaryTo(Type)` — N context pool acquire/release cycles. For many small primitives (int, bool, string) the per-call overhead may exceed a single bulk serialization.
|
|
|
|
**Possible optimization:** Batch fast-path — single serialization context for all parameters. Benchmark first.
|
|
|
|
### PROTO-3: Parameter serialization is AcBinary only
|
|
|
|
**Status:** Limitation
|
|
**Affects:** `SignalParams.SetParameterValues` / `GetParameterValues`
|
|
|
|
Uses `ToBinary()` / `BinaryTo()` exclusively. JSON parameter support would require dispatching on `DataSerializerType` + `AcJsonSerializer` reference. Low priority — binary is the primary transport.
|
|
|
|
## Transport
|
|
|
|
### TRANS-1: BufferWriterChunkSize defaults to 64KB for SignalR
|
|
|
|
**Status:** DONE
|
|
**Affects:** `AcBinaryHubProtocol` constructor, write path
|
|
|
|
`BufferWriterChunkSize = 4096` set in `AcBinaryHubProtocol` constructor. Aligns with Kestrel slab size, reduces latency-to-first-byte. Non-SignalR paths keep 64KB default.
|
|
|
|
### TRANS-2: WebSocket buffer sizes are hardcoded
|
|
|
|
**Status:** Acceptable
|
|
**Affects:** `AcSignalRClientBase` connection setup
|
|
|
|
Transport max message size (30MB) and application buffer (30MB) are hardcoded. Sufficient for current payloads but not configurable per-deployment.
|
|
|
|
## DataSource
|
|
|
|
### DS-1: GetAll returns raw byte[] for populate/merge
|
|
|
|
**Status:** By design
|
|
**Affects:** `AcSignalRDataSource.LoadDataSourceAsync`
|
|
|
|
The `GetAll` path uses `IsRawBytesData = true` to receive raw `byte[]` from the protocol, then deserializes into the existing list via `PopulateMerge`. This avoids allocating a temporary `List<T>` for merge. The extra copy (pipe → byte[]) is the trade-off.
|
|
|
|
**Possible optimization:** Direct typed deserialization with merge support in the deserializer (PopulateMerge from `ReadOnlySequence<byte>`). Requires deserializer API changes.
|
|
|
|
## Client-side Setup & DI
|
|
|
|
### CONN-1: HubConnectionBuilder inner DI isolation
|
|
|
|
**Status:** Workaround-in-place (dedicated options-passing overload)
|
|
**Affects:** Consumer client setup in `Program.cs` (MAUI, WASM, ASP.NET Core server prerender)
|
|
|
|
`HubConnectionBuilder.Services` is a separate `IServiceCollection` from the outer host DI. `services.Configure<AcBinaryHubProtocolOptions>(...)` registered in the outer container does NOT flow into `HubConnectionBuilder.Services`. Calling `hubBuilder.AddAcBinaryProtocol()` with no args silently falls back to default options.
|
|
|
|
**Known workaround:** Use the overload `AddAcBinaryProtocol(IHubConnectionBuilder, AcBinaryHubProtocolOptions, Action<...>? = null)` that accepts pre-resolved options explicitly. Canonical consumer pattern:
|
|
```csharp
|
|
var protocolOpts = sp.GetRequiredService<IOptions<AcBinaryHubProtocolOptions>>().Value;
|
|
hubBuilder.AddAcBinaryProtocol(protocolOpts);
|
|
```
|
|
|
|
## Dispatch
|
|
|
|
### DISPATCH-1: First-call null response (observed)
|
|
|
|
**Status:** Open — not diagnosed
|
|
**Affects:** `PostDataAsync<T>` awaiter / OnReceiveMessage → pending-request correlation
|
|
|
|
Observed symptom: first `GetProductDtos_80`-style call returns null despite server serializing and sending a valid ~80KB chunked response. Second call (client-side retry) works normally.
|
|
|
|
Log timeline:
|
|
- Server: `Serialize end (chunked) dataBytes=80571 chunkCount=20`
|
|
- Client: `Deserialize end (chunked)` — successful
|
|
- Client: `OnReceiveMessage ... requestId=5`
|
|
- Client: ~410ms later — `Client received null response. ... requestId=5`
|
|
- Client: auto-retry (requestId=6) → full 338 items
|
|
|
|
Hypothesis (unverified): `PostDataAsync<T>` awaiter's null-mapping path misroutes the parsed result, or `requestId → Task<T>` correlation has a race on the first response of a fresh connection. Client auto-retry hides the user-visible impact.
|
|
|
|
**Related TODO:** `SIGNALR_TODO.md#todo-01`
|
|
|
|
## Cross-cutting (also tracked in serializer-side docs)
|
|
|
|
### XCUT-1: JSON-in-Binary request parameters — cross-ref
|
|
|
|
Same tech debt as `../../AyCode.Core/docs/BINARY_ISSUES.md#xcut-1`. Planned replacement: migrate client→server request parameters from JSON-in-Binary envelope to direct Binary serialization. Coordinated change across all consuming projects.
|