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:
parent
6f60eaf310
commit
aed36a71cb
|
|
@ -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(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(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(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 *)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
// 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
|
namespace AyCode.Services.Nav.Ekaer.Models
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "3.0.1270.0")]
|
[System.CodeDom.Compiler.GeneratedCodeAttribute("XmlSchemaClassGenerator", "3.0.1270.0")]
|
||||||
[System.SerializableAttribute()]
|
[System.SerializableAttribute()]
|
||||||
[System.Xml.Serialization.XmlTypeAttribute("LocationType", Namespace="http://schemas.nav.gov.hu/EKAER/1.0/ekaermanagement")]
|
[System.Xml.Serialization.XmlTypeAttribute("LocationType", Namespace="http://schemas.nav.gov.hu/EKAER/1.0/ekaermanagement")]
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,19 @@ namespace AyCode.Services.SignalRs
|
||||||
Logger.Error(errorText);
|
Logger.Error(errorText);
|
||||||
throw new Exception(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);
|
Logger.Error(errorText);
|
||||||
throw new Exception(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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -183,8 +183,10 @@ public sealed class SignalResponseDataMessage : ISignalResponseMessage
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public T? GetResponseData<T>()
|
public T? GetResponseData<T>()
|
||||||
{
|
{
|
||||||
if (RawResponseData is T typed) return typed;
|
var data = RawResponseData;
|
||||||
return default;
|
if (data is T typed) return typed;
|
||||||
|
|
||||||
|
return data == null ? default : throw new InvalidCastException($"RawResponseData is NOT T! {typeof(T)} <> {data.GetType()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ Custom binary SignalR protocol, client infrastructure, message tagging, and seri
|
||||||
|
|
||||||
### Client
|
### 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.
|
- **`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)`.
|
- **`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.
|
- **`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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ Typed access via methods (PostDataJson pattern):
|
||||||
| Request + data | `byte[]` | typed object | client responds to server with data |
|
| Request + data | `byte[]` | typed object | client responds to server with data |
|
||||||
| Signal | null | null/empty | ping, status change, broadcast trigger |
|
| 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
|
## Request/Response Flow
|
||||||
|
|
||||||
|
|
@ -129,8 +129,8 @@ OnReceiveMessage(tag, requestId, signalParams, object data)
|
||||||
│ └─ { MessageTag, Status, DataSerializerType, RawResponseData = data }
|
│ └─ { MessageTag, Status, DataSerializerType, RawResponseData = data }
|
||||||
├─ Matching requestId in pending dict:
|
├─ Matching requestId in pending dict:
|
||||||
│ ├─ Route: null→sync wait, Action→invoke, Func<Task>→await
|
│ ├─ Route: null→sync wait, Action→invoke, Func<Task>→await
|
||||||
│ └─ GetResponseData<T>(): direct cast (T)RawResponseData
|
│ └─ GetResponseData<T>(): safe `is T` cast (mismatch → null, no throw)
|
||||||
│ Protocol already deserialized to correct type via SignalDataType
|
│ Protocol deserialized via SignalDataType = wire/server type (may ≠ caller's T)
|
||||||
└─ No match (broadcast):
|
└─ No match (broadcast):
|
||||||
└─ abstract MessageReceived(tag, signalParams, object data).Forget()
|
└─ abstract MessageReceived(tag, signalParams, object data).Forget()
|
||||||
```
|
```
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue