Improve SignalR client deserialization and docs

- Enhanced error handling in streaming methods of AcSignalRClientBase: deserialization errors are now logged and skipped instead of throwing.
- SignalResponseDataMessage.GetResponseData<T>() now throws InvalidCastException on type mismatch (was silent/null before).
- Updated README to document new casting and error behavior.
- Added Bash(dotnet workload *) command to settings.local.json.
- Removed GeneratedCode attribute from LocationType.cs.
This commit is contained in:
Loretta 2026-06-07 07:19:47 +02:00
parent 6f60eaf310
commit aed36a71cb
6 changed files with 36 additions and 11 deletions

View File

@ -138,7 +138,8 @@
"Bash(awk '/^; Assembly listing for method AyCode.Core.Tests.TestModels.TestOrder_All_False_GeneratedWriter:WriteProperties/{found=1} found && /^; Total bytes of code/{print; exit}' jitasm_tier1.txt)",
"Bash(sed -n '50108,58000p' jitasm_tier1.txt)",
"Bash(awk '/^; Assembly listing for method AyCode.Core.Tests.TestModels.TestOrder_All_False_GeneratedWriter:WriteProperties/{found=1; next} found && /^; Assembly listing for method/{exit} found && /mov[[:space:]]+byte[[:space:]]+ptr/{print}' jitasm_tier1.txt)",
"Bash(git -C \"H:/Applications/Aycode/Source/AyCode.Core\" log --oneline -15 -- \"AyCode.Core/Serializers/Toons/AcToonSerializer.ToonSerializationContext.cs\")"
"Bash(git -C \"H:/Applications/Aycode/Source/AyCode.Core\" log --oneline -15 -- \"AyCode.Core/Serializers/Toons/AcToonSerializer.ToonSerializationContext.cs\")",
"Bash(dotnet workload *)"
]
}
}

View File

@ -11,8 +11,6 @@
// xscgen --namespace http://schemas.nav.gov.hu/EKAER/1.0/ekaermanagement=AyCode.Services.Nav.Ekaer.Models --namespace http://schemas.nav.gov.hu/EKAER/1.0/common=AyCode.Services.Nav.Ekaer.Models.Common --nullable --separateFiles --output C:/Users/Fullepi/Downloads/ekaer/Generated2 C:/Users/Fullepi/Downloads/ekaer/ekaermanagement.xsd
namespace AyCode.Services.Nav.Ekaer.Models
{
[System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "3.0.1270.0")]
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute("LocationType", Namespace="http://schemas.nav.gov.hu/EKAER/1.0/ekaermanagement")]

View File

@ -226,7 +226,19 @@ namespace AyCode.Services.SignalRs
Logger.Error(errorText);
throw new Exception(errorText);
}
yield return responseMessage.GetResponseData<TResponseData>();
//yield return responseMessage.GetResponseData<TResponseData>();
TResponseData? item;
try
{
item = responseMessage.GetResponseData<TResponseData>();
}
catch (Exception ex)
{
Logger.Error($"Stream deser; tag {messageTag}", ex); continue;
}
yield return item;
}
}
}
@ -299,7 +311,19 @@ namespace AyCode.Services.SignalRs
Logger.Error(errorText);
throw new Exception(errorText);
}
yield return responseMessage.GetResponseData<TResponseData>();
//yield return responseMessage.GetResponseData<TResponseData>();
TResponseData? item;
try
{
item = responseMessage.GetResponseData<TResponseData>();
}
catch (Exception ex)
{
Logger.Error($"Stream deser; tag {messageTag}", ex); continue;
}
yield return item;
}
}
}

View File

@ -183,8 +183,10 @@ public sealed class SignalResponseDataMessage : ISignalResponseMessage
/// </summary>
public T? GetResponseData<T>()
{
if (RawResponseData is T typed) return typed;
return default;
var data = RawResponseData;
if (data is T typed) return typed;
return data == null ? default : throw new InvalidCastException($"RawResponseData is NOT T! {typeof(T)} <> {data.GetType()}");
}
}

View File

@ -14,7 +14,7 @@ Custom binary SignalR protocol, client infrastructure, message tagging, and seri
### Client
- **`AcSignalRClientBase.cs`** — Abstract SignalR client managing `HubConnection`, request/response tracking via pooled `SignalRRequestModel`. `SendCoreAsync` builds `SignalParams` (with `IsRawBytesData` when `T == byte[]`). CRUD helpers (Post, Get, GetAll, GetAllInto). Configurable timeouts.
- **`IAcSignalRHubClient.cs`** — Client interface + `SignalResponseDataMessage` (sealed, `RawResponseData` is `object?` — typed object or byte[], `GetResponseData<T>()` direct cast). Legacy message types (`IdMessage`, `SignalPostJsonDataMessage`) marked `[Obsolete]`.
- **`IAcSignalRHubClient.cs`** — Client interface + `SignalResponseDataMessage` (sealed, `RawResponseData` is `object?` — typed object or byte[], `GetResponseData<T>()` safe `is T` cast — type-mismatch returns null, does **not** throw). Legacy message types (`IdMessage`, `SignalPostJsonDataMessage`) marked `[Obsolete]`.
- **`IAcSignalRHubBase.cs`** — Base hub interface: `OnReceiveMessage(int messageTag, int? requestId, SignalParams signalParams, object data)`.
- **`ISignalParams.cs`** — `ISignalParams` base interface + `SignalParams` (Status, DataSerializerType, Parameters `byte[]?`, SignalDataType `string?`, IsRawBytesData `bool`). Metadata travels as separate hub argument (AcBinary serialized). Parameters and data are independent — both nullable in any direction.

View File

@ -106,7 +106,7 @@ Typed access via methods (PostDataJson pattern):
| Request + data | `byte[]` | typed object | client responds to server with data |
| Signal | null | null/empty | ping, status change, broadcast trigger |
`SignalResponseDataMessage` is an **internal DTO** for client-side callback routing and stream wire format — constructed in-memory from `signalParams` + `data`, never serialized as envelope on wire. `RawResponseData` is `object?` (typed object or byte[]). `GetResponseData<T>()` performs direct cast.
`SignalResponseDataMessage` is an **internal DTO** for client-side callback routing and stream wire format — constructed in-memory from `signalParams` + `data`, never serialized as envelope on wire. `RawResponseData` is `object?` (typed object or byte[]). `GetResponseData<T>()` performs a safe `is T` cast — type-mismatch returns null, does **not** throw (so a caller-requested subtype that differs from the wire type silently yields null, not an error).
## Request/Response Flow
@ -129,8 +129,8 @@ OnReceiveMessage(tag, requestId, signalParams, object data)
│ └─ { MessageTag, Status, DataSerializerType, RawResponseData = data }
├─ Matching requestId in pending dict:
│ ├─ Route: null→sync wait, Action→invoke, Func<Task>→await
│ └─ GetResponseData<T>(): direct cast (T)RawResponseData
│ Protocol already deserialized to correct type via SignalDataType
│ └─ GetResponseData<T>(): safe `is T` cast (mismatch → null, no throw)
│ Protocol deserialized via SignalDataType = wire/server type (may ≠ caller's T)
└─ No match (broadcast):
└─ abstract MessageReceived(tag, signalParams, object data).Forget()
```