OPC UA Foundation SDK .NET中OnSimpleWriteValue复杂数据返回byte[]问题
问题分析
在OPC UA服务器的OnSimpleWriteValue事件中,基础类型(int、float、string等)能正常读取,但处理实现IEncodable接口的复杂数据或其数组时,收到的是byte[]而非解码后的实体对象——当前解码逻辑未覆盖直接传入byte[]的场景,且解码方式存在错误。
解决方案
核心思路:先根据变量节点的DataType确定目标解码类型,再针对byte[]、ExtensionObject、ExtensionObject[]三种输入场景分别处理,确保正确解码为对应的实体类或数组。
修改后的关键代码
1. 修正OnPropertyChangedByOpc方法
private static ServiceResult OnPropertyChangedByOpc<P>(ISystemContext ctx, NodeState n, P property, object value) where P : PropertyChanged { var variableState = n as BaseVariableState; if (variableState == null) return ServiceResult.BadNodeIdUnknown; // 从变量节点的DataType获取目标解码类型 var dataTypeNodeId = variableState.DataType; var targetType = ctx.TypeTree.FindType(dataTypeNodeId); if (targetType == null) return ServiceResult.BadTypeDefinitionInvalid; object decodedValue = null; // 处理直接传入的byte[](复杂类型可能直接以二进制形式传递) if (value is byte[] rawBytes) { decodedValue = rawBytes.DecodeToType(targetType); } // 处理单个ExtensionObject else if (value is ExtensionObject extObj) { decodedValue = extObj.DecodeToType(targetType); } // 处理ExtensionObject数组(对应复杂类型数组) else if (value is ExtensionObject[] extArr) { var elementType = targetType.GetElementType(); if (elementType == null) return ServiceResult.BadTypeMismatch; var decodedArray = Array.CreateInstance(elementType, extArr.Length); for (int i = 0; i < extArr.Length; i++) { decodedArray.SetValue(extArr[i].DecodeToType(elementType), i); } decodedValue = decodedArray; } // 基础类型直接使用 else { decodedValue = value; } property.SetValue(decodedValue); return ServiceResult.Good; }
2. 新增/修正解码扩展方法
private static object DecodeToType(this byte[] rawBytes, Type targetType) { using var decoder = new BinaryDecoder(rawBytes, ServiceMessageContext.GlobalContext); // 直接解码到目标IEncodable类型,避免嵌套读取ExtensionObject的错误逻辑 return decoder.ReadEncodeable(null, targetType); } private static object DecodeToType(this ExtensionObject extObj, Type targetType) { if (extObj.Body is not byte[] bodyBytes) return null; return bodyBytes.DecodeToType(targetType); }
关键说明
- 类型匹配:通过变量节点的
DataType属性获取目标类型,确保解码类型与节点定义严格一致,避免依赖泛型参数的局限性。 - 全场景覆盖:处理了
byte[]直接传入、单个ExtensionObject、ExtensionObject数组三种复杂类型写入的常见场景。 - 解码逻辑修正:使用
ReadEncodeable直接解码到目标IEncodable类型,替代原代码中嵌套读取ExtensionObject的错误逻辑。 - 类型注册前提:确保你的
IEncodable实体类已通过TypeTree.RegisterType或对应方式注册到OPC UA类型系统中,否则解码会失败。
内容的提问来源于stack exchange,提问作者Teo230
相关产品推荐
相关产品推荐

