向OPC UA Server写入动态结构体数组遇BadTypeMismatch问题求助
OPC UA 结构体数组写入报 BadTypeMismatch 问题
我是OPC UA新手,用C#/.NetStandard程序连接西门子S7-1500 PLC的OPC UA Server,负责传输配置数据。写入基础数据类型、基础类型数组都正常,但PLC的自定义结构体无法在编译时确定,所以实现了动态创建结构体对象的机制,避免PLC新增结构体时更新应用版本。单个自定义结构体编码成字节数组写入正常,但写入该结构体数组时出现BadTypeMismatch错误。
单个结构体写入代码如下:
var nodeId = GetNodeId(path); Dictionary<uint, DataValue> nodeAttributes = ReadNodeAttributes(nodeId.ToString()); DataTypeNode dataTypeNode = (DataTypeNode)ReadNode(nodeAttributes[Attributes.DataType].ToString()); //Get the structure definition StructureDefinition structureDefinition = (StructureDefinition)dataTypeNode.DataTypeDefinition.Body; ExtensionObject ExtensionObject = new ExtensionObject(); ExtensionObject.TypeId = structureDefinition.DefaultEncodingId; ExtensionObject.Body = ConvertParameterToByteArray(parameter); DataValue dataValue = new DataValue(ExtensionObject); //Setup for the WriteValue WriteValue writeValue = new WriteValue(); writeValue.NodeId = nodeId; writeValue.Value = dataValue; writeValue.AttributeId = Attributes.Value; //Add the created value to the collection collection.Add(writeValue);
我原以为只要创建以元素数量开头、后续拼接各结构体字节数组的字节数组就能写入数组,但实际报错,请问问题出在哪里?
问题原因
你直接拼接元素数量+结构体字节数组的方式不符合OPC UA对结构体数组的编码规范,导致类型不匹配:
- OPC UA的结构体数组不是简单的长度+元素字节拼接,而是需要遵循UA二进制编码规则,数组节点的数据类型是该结构体的数组类型(而非单个结构体类型),你不能用单个结构体的编码逻辑直接套用到数组上。
- 单个结构体写入时,你传入的是对应结构体类型的
ExtensionObject,但数组节点要求的是**ExtensionObject数组**,且需要匹配数组类型的NodeId,手动拼接的字节数组无法被服务器识别为正确的数组类型。
正确解决方法
- 获取数组节点的正确数据类型:先读取数组节点的
DataType属性,该属性指向的是数组类型的NodeId,而非单个结构体的NodeId。 - 构造结构体元素的ExtensionObject集合:对每个结构体元素,沿用你之前单个写入的逻辑生成
ExtensionObject,将这些对象组成数组。 - 直接传入ExtensionObject数组到DataValue:客户端库会自动处理数组的编码,无需手动拼接字节。
修正后的示例代码
var nodeId = GetNodeId(path); Dictionary<uint, DataValue> nodeAttributes = ReadNodeAttributes(nodeId.ToString()); // 读取数组节点的DataType(指向数组类型的NodeId) DataTypeNode arrayDataTypeNode = (DataTypeNode)ReadNode(nodeAttributes[Attributes.DataType].ToString()); // 获取数组的元素类型:单个结构体的DataTypeNode DataTypeNode elementDataTypeNode = (DataTypeNode)ReadNode(arrayDataTypeNode.SubtypeOf.ToString()); StructureDefinition structureDefinition = (StructureDefinition)elementDataTypeNode.DataTypeDefinition.Body; // 假设parameterArray是待写入的结构体参数数组 List<ExtensionObject> extensionObjects = new List<ExtensionObject>(); foreach (var param in parameterArray) { ExtensionObject extObj = new ExtensionObject(); extObj.TypeId = structureDefinition.DefaultEncodingId; extObj.Body = ConvertParameterToByteArray(param); extensionObjects.Add(extObj); } // 直接将ExtensionObject数组作为DataValue的Value DataValue dataValue = new DataValue(extensionObjects.ToArray()); WriteValue writeValue = new WriteValue(); writeValue.NodeId = nodeId; writeValue.Value = dataValue; writeValue.AttributeId = Attributes.Value; collection.Add(writeValue);
关键注意事项
- 禁止手动拼接字节数组,依赖OPC UA客户端库完成编码,避免违反UA规范。
- 确保数组节点的
DataType指向正确的数组类型NodeId,而非单个结构体类型。 - 每个数组元素必须正确生成对应结构体的
ExtensionObject,再组成数组传入DataValue。
内容的提问来源于stack exchange,提问作者Sacha Saxer
相关产品推荐
相关产品推荐

