AyCode.Core/AyCode.Services.Server/docs/SIGNALR_SERVER.md

4.6 KiB

SignalR Server

Server-side SignalR hub infrastructure: method dispatch, session management, broadcast, and diagnostics. Source: SignalRs/ in this project.

For client-side transport (tags, wire protocol, client base) see AyCode.Services/docs/SIGNALR.md. For the DataSource collection see SIGNALR_DATASOURCE.md.

Server Processing

6. OnReceiveMessage(tag, requestId, signalParams, SignalData data)
7. Extract parameterBytes from signalParams.Parameters
8. DynamicMethodRegistry.GetMethodByMessageTag(tag)      <- ConcurrentDictionary lookup
9. signalParams.GetParameterValues(paramInfos):
   |- byte[] -> BinaryTo<byte[][]>() (cached)
   |- Per-element: byte[][i].BinaryTo(paramInfos[i].ParameterType)
   |- Trailing defaults auto-filled
   |- Hub validates: missing required params throw ArgumentException
   '- NOTE: BinaryTo only -- JSON param deserialization not supported (needs JsonTo + project ref)
10. MethodInfo.InvokeMethod(instance, params)              <- unwraps Task/ValueTask
11. CreateResponseMessage(tag, Success, result)            <- Binary serialize payload -> byte[]
12. SendMessageToClient(caller, tag, message, requestId):
    |- Extract signalParams { Status, DataSerializerType } + SignalData from message
    '- caller.OnReceiveMessage(tag, requestId, signalParams, SignalData)
        (metadata + payload as separate args -- no envelope serialization)
13. If SendToOtherClientType != None:
    '- SendMessageToOthers(sendToOtherClientTag, result) <- uses sendToOtherClientTag, not messageTag

Dynamic Method Dispatch

See also: AyCode.Models.Server/DynamicMethods/README.md

Server-Side Lookup

1. OnReceiveMessage(tag=100, requestId, signalParams, SignalData data)

2. DynamicMethodRegistry.GetMethodByMessageTag(100)
   |- Check static ConcurrentDictionary<int, (Type, AcMethodInfoModel)?> cache
   |- Hit? -> find instance of cached Type from registered instances
   |- Miss? -> scan all registered instances' methods for [SignalR(100)]
   |          cache the result (including negative = null)
   '- Return (instance, methodInfoModel) or null

3. AcMethodInfoModel contains:
   |- MethodInfo (the method to invoke)
   |- SignalRAttribute (tag, sendToOtherClientTag, sendToOtherClientType)
   '- ParamInfos[] (ParameterInfo for deserialization)

The DynamicMethodRegistry uses a static ConcurrentDictionary for the global tag->method cache.

Registration

The hub registers service instances during initialization:

DynamicMethodRegistry.Register(myService);    // scans [SignalR(tag)] methods lazily
DynamicMethodRegistry.Register(anotherService);

Reflection runs lazily per tag on first request, then results are cached statically.

Session Management

AcSessionService<TSessionItem, TSessionItemId> tracks connected clients:

ConcurrentDictionary<TSessionItemId, TSessionItem> Sessions

IAcSessionItem<TSessionItemId> requires SessionId property. Used for targeting messages to specific users/connections.

Broadcast Service

AcSignalRSendToClientService<THub, TTags, TLogger> provides server-push methods:

Method Target
SendMessageToAllClients All connected
SendMessageToConnection(connectionId) Single connection
SendMessageToUser(userId) User (all connections)
SendMessageToUsers(userIds) Multiple users

All messages serialized to SignalData payload + SignalParams metadata (Parameters=null for server->client push) -> sent as separate hub arguments via OnReceiveMessage (no envelope wrapping). Server wraps byte[] in non-pooled SignalData; client receives as ArrayPool-backed SignalData via AyCodeBinaryHubProtocol.

Hub Events

  • OnConnectedAsync() -- log connection
  • OnDisconnectedAsync(exception) -- log disconnection, cleanup session

Diagnostics

Enable with AcWebSignalRHubBase.EnableBinaryDiagnostics = true.

Logs: hex dump (500 byte sample), header parsing (version, marker), property count + names via VarUInt reading.

SignalResponseDataMessage.DiagnosticLogger -- per-response logging: target type info, property list, inheritance chain, hex dump. Uses SignalData.Span for zero-alloc diagnostics.

Key Source Files

Component Path
Hub base SignalRs/AcWebSignalRHubBase.cs
Session service SignalRs/AcSessionService.cs
Broadcast service SignalRs/AcSignalRSendToClientService.cs
Logger hub SignalRs/AcLoggerSignalRHub.cs
Tracking helpers SignalRs/TrackingItemHelpers.cs
Dynamic dispatch AyCode.Models.Server/DynamicMethods/AcDynamicMethodRegistry.cs