You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

向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,手动拼接的字节数组无法被服务器识别为正确的数组类型。

正确解决方法

  1. 获取数组节点的正确数据类型:先读取数组节点的DataType属性,该属性指向的是数组类型的NodeId,而非单个结构体的NodeId。
  2. 构造结构体元素的ExtensionObject集合:对每个结构体元素,沿用你之前单个写入的逻辑生成ExtensionObject,将这些对象组成数组。
  3. 直接传入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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 00:26:37