如何在OPCFoundation.NetStandard.Opc.Ua.Server中编程实现结构类型定义与使用?
OPC UA服务器编程创建结构类型、变量节点及赋值(C#)
1. 定义C#数据类(支持枚举与嵌套结构)
先定义需映射到OPC UA结构类型的C#类,通过DataContract和DataMember特性实现序列化支持:
using System.Runtime.Serialization; // 基础Person类 [DataContract(Name = "Person")] public class Person { [DataMember] public string Name { get; set; } [DataMember] public int Age { get; set; } } // 枚举类型 [DataContract(Name = "Gender")] public enum Gender { [EnumMember] Unknown, [EnumMember] Male, [EnumMember] Female } // 嵌套结构 [DataContract(Name = "Address")] public class Address { [DataMember] public string Street { get; set; } [DataMember] public string City { get; set; } } // 包含枚举与嵌套结构的复杂类 [DataContract(Name = "Employee")] public class Employee : Person { [DataMember] public Gender Gender { get; set; } [DataMember] public Address WorkAddress { get; set; } }
2. 在OPC UA服务器中注册结构类型
在服务器地址空间初始化阶段(重写CreateAddressSpace方法),将自定义结构类型注册到OPC UA服务器:
using Opc.Ua; using Opc.Ua.Server; public class CustomNodeManager : NodeManager { public CustomNodeManager(IServerInternal server, ApplicationConfiguration configuration) : base(server, configuration) { NamespaceUris.Add("http://your-custom-namespace.com"); } protected override void CreateAddressSpace(IDictionary<NodeId, INode> addressSpace) { base.CreateAddressSpace(addressSpace); var namespaceIndex = Server.NamespaceUris.GetIndex("http://your-custom-namespace.com"); // 批量注册自定义类型 RegisterEncodeableType(typeof(Person), namespaceIndex, addressSpace); RegisterEncodeableType(typeof(Gender), namespaceIndex, addressSpace); RegisterEncodeableType(typeof(Address), namespaceIndex, addressSpace); RegisterEncodeableType(typeof(Employee), namespaceIndex, addressSpace); } private void RegisterEncodeableType(Type type, ushort namespaceIndex, IDictionary<NodeId, INode> addressSpace) { var encodeableType = EncodeableType.GetEncodeableType(type); if (encodeableType == null) { encodeableType = new EncodeableType(type, null, namespaceIndex); EncodeableType.RegisterEncodeableType(encodeableType); } var typeNodeId = new NodeId(encodeableType.Name, namespaceIndex); if (!addressSpace.ContainsKey(typeNodeId)) { var typeNode = new StructuredTypeNode { NodeId = typeNodeId, BrowseName = new QualifiedName(encodeableType.Name, namespaceIndex), DisplayName = new LocalizedText(encodeableType.Name), Description = new LocalizedText($"自定义结构类型:{encodeableType.Name}"), WriteMask = AttributeWriteMask.None, UserWriteMask = AttributeWriteMask.None, IsAbstract = false }; AddNode(typeNode); } } }
3. 创建结构类型的变量节点
在地址空间中创建使用自定义结构类型的变量节点:
// 在CustomNodeManager的CreateAddressSpace方法中继续添加: var namespaceIndex = Server.NamespaceUris.GetIndex("http://your-custom-namespace.com"); // 创建Person类型变量节点 var personVariable = new VariableNode { NodeId = new NodeId("PersonVariable", namespaceIndex), BrowseName = new QualifiedName("PersonVariable", namespaceIndex), DisplayName = new LocalizedText("Person变量"), Description = new LocalizedText("Person类型的变量"), DataType = new NodeId("Person", namespaceIndex), ValueRank = ValueRanks.Scalar, AccessLevel = AccessLevels.CurrentRead | AccessLevels.CurrentWrite, UserAccessLevel = AccessLevels.CurrentRead | AccessLevels.CurrentWrite, MinimumSamplingInterval = 100, Historizing = false }; AddNode(personVariable); // 创建Employee类型变量节点 var employeeVariable = new VariableNode { NodeId = new NodeId("EmployeeVariable", namespaceIndex), BrowseName = new QualifiedName("EmployeeVariable", namespaceIndex), DisplayName = new LocalizedText("Employee变量"), Description = new LocalizedText("Employee类型的变量"), DataType = new NodeId("Employee", namespaceIndex), ValueRank = ValueRanks.Scalar, AccessLevel = AccessLevels.CurrentRead | AccessLevels.CurrentWrite, UserAccessLevel = AccessLevels.CurrentRead | AccessLevels.CurrentWrite, MinimumSamplingInterval = 100, Historizing = false }; AddNode(employeeVariable);
4. 为变量节点设置值
创建结构实例并赋值给对应变量节点:
// 设置Person变量值 var personInstance = new Person { Name = "John Doe", Age = 30 }; Server.InternalNodeManager.Write(new WriteValue { NodeId = new NodeId("PersonVariable", namespaceIndex), AttributeId = Attributes.Value, Value = new DataValue(new Variant(personInstance)) }); // 设置Employee变量值(包含枚举与嵌套结构) var employeeInstance = new Employee { Name = "Jane Smith", Age = 28, Gender = Gender.Female, WorkAddress = new Address { Street = "123 Main St", City = "New York" } }; Server.InternalNodeManager.Write(new WriteValue { NodeId = new NodeId("EmployeeVariable", namespaceIndex), AttributeId = Attributes.Value, Value = new DataValue(new Variant(employeeInstance)) });
关键注意事项
- 自定义类的
DataContract名称需与OPC UA结构类型名称完全一致 - 枚举成员必须添加
EnumMember特性,否则无法被OPC UA识别 - 嵌套结构需单独注册,确保服务器类型树能正确解析依赖关系
- 变量节点的
DataType属性必须指向对应结构类型的NodeId
内容的提问来源于stack exchange,提问作者Tobus




