From a77bcee7a3b1ad934cc52b33b4106920c1e82c88 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 7 Jan 2026 20:00:48 +0000 Subject: [PATCH 1/4] Initial plan From a3fbd60794051dc921477f12c176db4d7f5ee1ac Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 7 Jan 2026 20:12:54 +0000 Subject: [PATCH 2/4] Fix StatusCode casting from uint in encoders Fixed InvalidCastException when encoding StatusCode values that are stored as uint in object variables. Changed explicit casts to use pattern matching to handle both StatusCode and uint types properly. - XmlEncoder.WriteVariantContents: Line 1930 - BinaryEncoder: Line 2440 - JsonEncoder: Line 3351 - UadpDataSetMessage: Line 810 Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> --- Libraries/Opc.Ua.PubSub/Encoding/UadpDataSetMessage.cs | 2 +- Stack/Opc.Ua.Core/Types/Encoders/JsonEncoder.cs | 2 +- Stack/Opc.Ua.Types/Encoders/BinaryEncoder.cs | 2 +- Stack/Opc.Ua.Types/Encoders/XmlEncoder.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Libraries/Opc.Ua.PubSub/Encoding/UadpDataSetMessage.cs b/Libraries/Opc.Ua.PubSub/Encoding/UadpDataSetMessage.cs index d29c96996..9a85dd82e 100644 --- a/Libraries/Opc.Ua.PubSub/Encoding/UadpDataSetMessage.cs +++ b/Libraries/Opc.Ua.PubSub/Encoding/UadpDataSetMessage.cs @@ -807,7 +807,7 @@ private void EncodeFieldAsRawData( valueToEncode as ExpandedNodeId); break; case BuiltInType.StatusCode: - binaryEncoder.WriteStatusCode("StatusCode", (StatusCode)valueToEncode); + binaryEncoder.WriteStatusCode("StatusCode", valueToEncode is StatusCode sc ? sc : new StatusCode((uint)valueToEncode)); break; case BuiltInType.XmlElement: binaryEncoder.WriteXmlElement( diff --git a/Stack/Opc.Ua.Core/Types/Encoders/JsonEncoder.cs b/Stack/Opc.Ua.Core/Types/Encoders/JsonEncoder.cs index fd9dedf7e..c56d4d156 100644 --- a/Stack/Opc.Ua.Core/Types/Encoders/JsonEncoder.cs +++ b/Stack/Opc.Ua.Core/Types/Encoders/JsonEncoder.cs @@ -3348,7 +3348,7 @@ public void WriteVariantContents(object value, TypeInfo typeInfo) WriteExpandedNodeId(null, (ExpandedNodeId)value); return; case BuiltInType.StatusCode: - WriteStatusCode(null, (StatusCode)value); + WriteStatusCode(null, value is StatusCode sc ? sc : new StatusCode((uint)value)); return; case BuiltInType.QualifiedName: WriteQualifiedName(null, (QualifiedName)value); diff --git a/Stack/Opc.Ua.Types/Encoders/BinaryEncoder.cs b/Stack/Opc.Ua.Types/Encoders/BinaryEncoder.cs index 027dc642c..1ae54f379 100644 --- a/Stack/Opc.Ua.Types/Encoders/BinaryEncoder.cs +++ b/Stack/Opc.Ua.Types/Encoders/BinaryEncoder.cs @@ -2437,7 +2437,7 @@ private void WriteVariantValue(string fieldName, Variant value) WriteExpandedNodeId(null, (ExpandedNodeId)valueToEncode); return; case BuiltInType.StatusCode: - WriteStatusCode(null, (StatusCode)valueToEncode); + WriteStatusCode(null, valueToEncode is StatusCode sc ? sc : new StatusCode((uint)valueToEncode)); return; case BuiltInType.QualifiedName: WriteQualifiedName(null, (QualifiedName)valueToEncode); diff --git a/Stack/Opc.Ua.Types/Encoders/XmlEncoder.cs b/Stack/Opc.Ua.Types/Encoders/XmlEncoder.cs index 42b7dbe51..6ff64508c 100644 --- a/Stack/Opc.Ua.Types/Encoders/XmlEncoder.cs +++ b/Stack/Opc.Ua.Types/Encoders/XmlEncoder.cs @@ -1927,7 +1927,7 @@ public void WriteVariantContents(object value, TypeInfo typeInfo) WriteExpandedNodeId("ExpandedNodeId", (ExpandedNodeId)value); return; case BuiltInType.StatusCode: - WriteStatusCode("StatusCode", (StatusCode)value); + WriteStatusCode("StatusCode", value is StatusCode sc ? sc : new StatusCode((uint)value)); return; case BuiltInType.QualifiedName: WriteQualifiedName("QualifiedName", (QualifiedName)value); From e8add9ddaa8b6cc99f90944245ddcae4e58cc4a3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 8 Jan 2026 21:11:56 +0000 Subject: [PATCH 3/4] Fix additional StatusCode casting issues in FilterEvaluator, BaseComplexType, GDS classes Applied same pattern matching fix to handle StatusCode values that may be stored as uint: - FilterEvaluator.cs: Lines 833 and 1470 - BaseComplexType.cs: Line 488 - GlobalDiscoveryServerClient.cs: Line 1016 - Opc.Ua.Gds.Classes.cs: Line 3156 All projects build successfully and encoder tests pass (5969 tests, 0 failures). Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> --- .../Opc.Ua.Client.ComplexTypes/Types/BaseComplexType.cs | 5 ++++- .../Opc.Ua.Gds.Client.Common/GlobalDiscoveryServerClient.cs | 2 +- .../Opc.Ua.Gds.Server.Common/Model/Opc.Ua.Gds.Classes.cs | 2 +- Stack/Opc.Ua.Core/Stack/Types/FilterEvaluator.cs | 4 ++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Libraries/Opc.Ua.Client.ComplexTypes/Types/BaseComplexType.cs b/Libraries/Opc.Ua.Client.ComplexTypes/Types/BaseComplexType.cs index d79d27573..6624e21f9 100644 --- a/Libraries/Opc.Ua.Client.ComplexTypes/Types/BaseComplexType.cs +++ b/Libraries/Opc.Ua.Client.ComplexTypes/Types/BaseComplexType.cs @@ -485,7 +485,10 @@ private void EncodeProperty( encoder.WriteExpandedNodeId(name, (ExpandedNodeId)property.GetValue(this)); break; case BuiltInType.StatusCode: - encoder.WriteStatusCode(name, (StatusCode)property.GetValue(this)); + { + var propValue = property.GetValue(this); + encoder.WriteStatusCode(name, propValue is StatusCode sc ? sc : new StatusCode((uint)propValue)); + } break; case BuiltInType.DiagnosticInfo: encoder.WriteDiagnosticInfo(name, (DiagnosticInfo)property.GetValue(this)); diff --git a/Libraries/Opc.Ua.Gds.Client.Common/GlobalDiscoveryServerClient.cs b/Libraries/Opc.Ua.Gds.Client.Common/GlobalDiscoveryServerClient.cs index c1ef8089b..f310b92ef 100644 --- a/Libraries/Opc.Ua.Gds.Client.Common/GlobalDiscoveryServerClient.cs +++ b/Libraries/Opc.Ua.Gds.Client.Common/GlobalDiscoveryServerClient.cs @@ -1013,7 +1013,7 @@ public void CheckRevocationStatus( if (outputArguments.Count >= 2) { - certificateStatus = (StatusCode)outputArguments[0]; + certificateStatus = outputArguments[0] is StatusCode sc ? sc : new StatusCode((uint)outputArguments[0]); validityTime = (DateTime)outputArguments[1]; } return (certificateStatus, validityTime); diff --git a/Libraries/Opc.Ua.Gds.Server.Common/Model/Opc.Ua.Gds.Classes.cs b/Libraries/Opc.Ua.Gds.Server.Common/Model/Opc.Ua.Gds.Classes.cs index 406f4653a..fac6c9aa7 100644 --- a/Libraries/Opc.Ua.Gds.Server.Common/Model/Opc.Ua.Gds.Classes.cs +++ b/Libraries/Opc.Ua.Gds.Server.Common/Model/Opc.Ua.Gds.Classes.cs @@ -3153,7 +3153,7 @@ protected override ServiceResult Call( byte[] certificate = (byte[])_inputArguments[0]; - StatusCode certificateStatus = (StatusCode)_outputArguments[0]; + StatusCode certificateStatus = _outputArguments[0] is StatusCode sc ? sc : new StatusCode((uint)_outputArguments[0]); DateTime validityTime = (DateTime)_outputArguments[1]; if (OnCall != null) diff --git a/Stack/Opc.Ua.Core/Stack/Types/FilterEvaluator.cs b/Stack/Opc.Ua.Core/Stack/Types/FilterEvaluator.cs index b8691dc3e..d2d6ea998 100644 --- a/Stack/Opc.Ua.Core/Stack/Types/FilterEvaluator.cs +++ b/Stack/Opc.Ua.Core/Stack/Types/FilterEvaluator.cs @@ -830,7 +830,7 @@ private object ToUInt16(object value, BuiltInType sourceType) case BuiltInType.String: return XmlConvert.ToUInt16((string)value); case BuiltInType.StatusCode: - var code = (StatusCode)value; + var code = value is StatusCode sc ? sc : new StatusCode((uint)value); return (ushort)(code.CodeBits >> 16); case >= BuiltInType.Null and <= BuiltInType.Enumeration: // conversion not supported. @@ -1467,7 +1467,7 @@ private object ToStatusCode(object value, BuiltInType sourceType) switch (sourceType) { case BuiltInType.StatusCode: - return (StatusCode)value; + return value is StatusCode sc ? sc : new StatusCode((uint)value); case BuiltInType.UInt16: uint code = Convert.ToUInt32((ushort)value); code <<= 16; From 3df4f8947e3aa605e1041e8a318ef995cec7133b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 8 Jan 2026 21:18:30 +0000 Subject: [PATCH 4/4] Fix additional StatusCode casting issues in TypeInfo and DataComparer Applied pattern matching fix to handle StatusCode values in: - TypeInfo.cs: Lines 2475 and 3048 (conversion functions) - DataComparer.cs: Line 760 (comparison function) All builds successful and encoder tests pass (5969 tests, 0 failures). Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> --- Stack/Opc.Ua.Core/Types/Utils/DataComparer.cs | 4 +++- Stack/Opc.Ua.Types/Utils/TypeInfo.cs | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Stack/Opc.Ua.Core/Types/Utils/DataComparer.cs b/Stack/Opc.Ua.Core/Types/Utils/DataComparer.cs index 3f0ed3501..8c5d5a902 100644 --- a/Stack/Opc.Ua.Core/Types/Utils/DataComparer.cs +++ b/Stack/Opc.Ua.Core/Types/Utils/DataComparer.cs @@ -757,7 +757,9 @@ public bool CompareVariant(Variant value1, Variant value2) } if (systemType == typeof(StatusCode)) { - return CompareStatusCode((StatusCode)value1.Value, (StatusCode)value2.Value); + var sc1 = value1.Value is StatusCode s1 ? s1 : new StatusCode((uint)value1.Value); + var sc2 = value2.Value is StatusCode s2 ? s2 : new StatusCode((uint)value2.Value); + return CompareStatusCode(sc1, sc2); } if (systemType == typeof(DiagnosticInfo)) { diff --git a/Stack/Opc.Ua.Types/Utils/TypeInfo.cs b/Stack/Opc.Ua.Types/Utils/TypeInfo.cs index c466c1988..36d06488e 100644 --- a/Stack/Opc.Ua.Types/Utils/TypeInfo.cs +++ b/Stack/Opc.Ua.Types/Utils/TypeInfo.cs @@ -2472,7 +2472,7 @@ private static ushort ToUInt16(object value, TypeInfo sourceType) case BuiltInType.String: return XmlConvert.ToUInt16((string)value); case BuiltInType.StatusCode: - var code = (StatusCode)value; + var code = value is StatusCode sc ? sc : new StatusCode((uint)value); return (ushort)(code.CodeBits >> 16); case >= BuiltInType.Null and <= BuiltInType.Enumeration: // conversion not supported. @@ -3045,7 +3045,7 @@ private static StatusCode ToStatusCode(object value, TypeInfo sourceType) switch (sourceType.BuiltInType) { case BuiltInType.StatusCode: - return (StatusCode)value; + return value is StatusCode sc ? sc : new StatusCode((uint)value); case BuiltInType.UInt16: uint code = Convert.ToUInt32((ushort)value, CultureInfo.InvariantCulture); code <<= 16;