fix(siteruntime): decode List value to typed array before DCL write (OPC UA array write path)

This commit is contained in:
Joseph Doherty
2026-06-16 16:48:28 -04:00
parent 734c161383
commit 94be5e813b
3 changed files with 147 additions and 9 deletions
@@ -431,11 +431,37 @@ public class InstanceActor : ReceiveActor
return;
}
// MV (C1): for a data-sourced List attribute the incoming command.Value is
// the canonical JSON array string (ScopeAccessors encodes the script's
// List<T> for transport/storage). Writing that string straight to the DCL
// would push a String scalar to an array node. Decode it back to a typed
// List<T> so the DCL/Variant write produces a real array. A non-empty value
// that fails to decode (malformed JSON / bad element) is poison — reject the
// write rather than forward garbage to the device (mirrors the static-path
// rejection in HandleSetStaticAttributeCore). Scalars are unchanged.
object? writeValue = command.Value;
if (IsListAttribute(resolved) && !string.IsNullOrWhiteSpace(command.Value))
{
var decoded = DecodeAttributeValue(resolved, command.Value);
if (decoded == null)
{
_logger.LogWarning(
"SetAttribute rejected — value for data-sourced List attribute '{Attribute}' on instance '{Instance}' is not a valid list",
attributeName, instanceName);
caller.Tell(new SetStaticAttributeResponse(
correlationId, instanceName, attributeName, false,
$"Invalid list value for attribute '{attributeName}'", DateTimeOffset.UtcNow));
return;
}
writeValue = decoded;
}
var writeRequest = new WriteTagRequest(
correlationId,
resolved.BoundDataConnectionName!,
resolved.DataSourceReference!,
command.Value,
writeValue,
DateTimeOffset.UtcNow);
// Ask the DCL and pipe the result back to the original caller. The DCL