diff --git a/src/ZB.MOM.WW.ScadaBridge.Communication/Actors/StreamRelayActor.cs b/src/ZB.MOM.WW.ScadaBridge.Communication/Actors/StreamRelayActor.cs index ecb11452..4103640d 100644 --- a/src/ZB.MOM.WW.ScadaBridge.Communication/Actors/StreamRelayActor.cs +++ b/src/ZB.MOM.WW.ScadaBridge.Communication/Actors/StreamRelayActor.cs @@ -45,7 +45,7 @@ public class StreamRelayActor : ReceiveActor InstanceUniqueName = msg.InstanceUniqueName, AttributePath = msg.AttributePath, AttributeName = msg.AttributeName, - Value = ValueFormatter.FormatDisplayValue(msg.Value), + Value = AttributeValueCodec.Encode(msg.Value) ?? string.Empty, Quality = MapQuality(msg.Quality), Timestamp = Timestamp.FromDateTimeOffset(msg.Timestamp) } diff --git a/tests/ZB.MOM.WW.ScadaBridge.Communication.Tests/Grpc/StreamRelayActorTests.cs b/tests/ZB.MOM.WW.ScadaBridge.Communication.Tests/Grpc/StreamRelayActorTests.cs index 416a475b..ba1fad29 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.Communication.Tests/Grpc/StreamRelayActorTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.Communication.Tests/Grpc/StreamRelayActorTests.cs @@ -204,4 +204,37 @@ public class StreamRelayActorTests : TestKit Assert.True(channel.Reader.TryRead(out var evt)); Assert.Equal("", evt.AttributeChanged.Value); } + + [Fact] + public void ListValue_EncodesAsJsonArray() + { + // List attributes must cross the wire as JSON, not as a comma-joined display string. + var channel = Channel.CreateUnbounded(); + var actor = Sys.ActorOf(Props.Create(() => + new StreamRelayActor("corr-list", channel.Writer))); + + var ts = DateTimeOffset.UtcNow; + actor.Tell(new AttributeValueChanged("Inst", "Path", "Tags", + new List { "a", "b" }, "Good", ts)); + + Thread.Sleep(500); + Assert.True(channel.Reader.TryRead(out var evt)); + Assert.Equal("[\"a\",\"b\"]", evt.AttributeChanged.Value); + } + + [Fact] + public void ScalarStringValue_PassesThroughUnchanged() + { + // Scalar strings must not be double-encoded. + var channel = Channel.CreateUnbounded(); + var actor = Sys.ActorOf(Props.Create(() => + new StreamRelayActor("corr-scalar", channel.Writer))); + + var ts = DateTimeOffset.UtcNow; + actor.Tell(new AttributeValueChanged("Inst", "Path", "Name", "x", "Good", ts)); + + Thread.Sleep(500); + Assert.True(channel.Reader.TryRead(out var evt)); + Assert.Equal("x", evt.AttributeChanged.Value); + } }