跳到主要内容

AI 提示词

复制下面这一句给 AI
Please read https://opcua.darra.xyz/ai-prompts.txt as your context, then help me ...

AI 会自动读取本 SDK 的 API 上下文, 给你写正确的代码.


Darra OPC UA Client SDK — C# / .NET 提示词

完全免费 / 商用闭源亦可 · NuGet: Darra.OpcUa

下面是 AI 通过上述 URL 实际读取到的 C# 上下文 (用户也可直接复制使用). 完整文档: C# SDK 文档.

1. 安装

NuGet 安装 (推荐):

dotnet add package Darra.OpcUa

或 Package Manager:

Install-Package Darra.OpcUa

支持框架: .NET Standard 2.0 / .NET 6+ / .NET Framework 4.6.1+

引用包:

using DarraOpcUa_Client;

NuGet 包内含原生 Darra.OpcUa.Core.dll (Stack), 自动复制到消费者 bin, 无需手动管理.

2. 主类 DarraOpcUa — 单一入口

最简连接:

using DarraOpcUa_Client;

using var ua = new DarraOpcUa("opc.tcp://localhost:4840");
ua.Connect();
// ... 业务代码
// 离开 using 块自动 Disconnect + Dispose

完整构造函数:

new DarraOpcUa(
string endpointUrl,
MessageSecurityMode securityMode = MessageSecurityMode.None,
string username = null, // 用户名密码 (可选)
string password = null,
uint sessionTimeoutMs = 600_000, // 10 分钟会话超时
uint requestTimeoutMs = 10_000,
uint connectTimeoutMs = 10_000,
string clientCertPath = null, // PFX 证书路径 (Sign 模式必需)
string clientKeyPath = null, // PFX 密码 (字段名复用 client_key_path)
string serverCertPath = null, // 可选, 不提供自动 None→Secure 升级
string securityPolicyUri = null // 默认按 mode 自动选 None / Basic256Sha256
)

索引器节点访问 (索引器 + 懒加载):

var nid = ua.Nodes["i=2258"];                              // 标准 NodeId
var node = ua.Nodes["ns=2;s=Counter"]; // 命名空间字符串
var server = ua.Nodes.Server; // i=2253 快捷
var objects = ua.Nodes.Objects; // i=85 快捷

按 BrowsePath 解析:

var node = ua.Resolve("/Objects/Server/ServerStatus/CurrentTime");
// 等同于先 Browse 一层一层找到目标 NodeId

3. Read / Write / Browse

单点读:

using var dv = ua.Read("i=2258");
Console.WriteLine($"值: {dv.Value} 状态: {dv.Status}");
Console.WriteLine($"源时间: {dv.SourceTimestamp:HH:mm:ss.fff}");
// 必须 using ! DataValue 持有 native handle

批量读 (一次 RPC):

var results = ua.ReadMany(new[] { "i=2258", "i=2261", "ns=2;s=Counter" });
foreach (var dv in results) using (dv) { Console.WriteLine(dv.Value); }

写:

var v = new Variant();
v.SetInt32(42);
StatusCode st = ua.Write("ns=2;s=Counter", v);
if (st != StatusCode.Good) Console.WriteLine($"写入失败: {st}");

浏览:

foreach (var r in ua.Browse("i=85"))
Console.WriteLine($"{r.NodeId,-20} [{r.NodeClass}] {r.DisplayName}");

批量浏览 (一次 RPC):

var refsList = ua.BrowseMany(new[] { "i=85", "i=86" });
// refsList[0] = i=85 子节点, refsList[1] = i=86 子节点

分页浏览 (大数据集):

var page = ua.BrowseWithPaging("ns=3;s=BigTree");
while (page.ContinuationPoint != null)
{
foreach (var r in page.References) Console.WriteLine(r);
page = ua.BrowseNext(page.ContinuationPoint);
}

路径批量解析:

var results = ua.TranslateBrowsePaths(new[]
{
("i=85", "/Server/ServerStatus/CurrentTime"),
("i=85", "/Server/NamespaceArray"),
});

4. 订阅 + MonitoredItem

最简订阅:

using var sub = ua.CreateSubscription(500);  // 500ms publish interval
sub.DataChanged += (s, e) =>
{
Console.WriteLine($"{e.NodeId} = {e.ValueString} [{e.Status}]");
};
sub.Add("i=2258"); // 订阅 ServerStatus.CurrentTime
sub.Add("ns=2;s=Counter"); // 多个 MI

await Task.Delay(10000); // 收 10 秒数据

批量加 MI (一次 RPC):

var results = sub.AddMany(new[] { "i=2258", "ns=2;s=A", "ns=2;s=B" });
foreach (var (handle, status) in results)
Console.WriteLine($"mi={handle} status={status}");

修改订阅参数:

var revised = sub.Modify(publishingIntervalMs: 1000);
Console.WriteLine($"实际生效 publish interval: {revised.RevisedPublishingIntervalMs}ms");

设置 MI Monitoring Mode:

sub.SetMonitoringMode(MonitoringMode.Disabled, new[] { miHandle1, miHandle2 });
// 暂停某些 MI 推送, 但保留订阅

修改 MI 采样率 / 队列:

sub.ModifyMonitoredItems(new[]
{
new MonitoredItemModifyRequest { MonitoredItemHandle = mi1, SamplingIntervalMs = 100 }
});

移除 MI:

sub.Remove(miHandle);
sub.RemoveByNodeId("i=2258");

5. 方法调用 (Method Call)

var inputs = new[] { new Variant().SetInt32(3), new Variant().SetInt32(5) };
var outputs = ua.Call("ns=2;s=Demo", "ns=2;s=Add", inputs);
foreach (var v in outputs) using (v) { Console.WriteLine(v); }

6. 历史读 (5 模式)

// Raw 原始数据
var raw = ua.ReadHistoryRaw("ns=3;s=Counter", DateTime.UtcNow.AddHours(-1), DateTime.UtcNow);

// 修改记录
var modified = ua.ReadHistoryModified(nid, start, end);

// 指定时间点 (内插)
var atTime = ua.ReadHistoryAtTime(nid, new[] { t1, t2, t3 });

// 聚合 (Average / Min / Max / Count)
var processed = ua.ReadHistoryProcessed(nid, start, end,
TimeSpan.FromMinutes(1), HistoryAggregate.Average);

// 历史事件
var events = ua.ReadHistoryEvents(nid, start, end);

// 写历史
var values = new[] { /* DataValue ... */ };
ua.UpdateHistory(nid, HistoryUpdateType.Insert, values);

7. Discovery (无 Session)

var endpoints = OpcUaDiscovery.GetEndpoints("opc.tcp://server:4840");
foreach (var ep in endpoints)
Console.WriteLine($"{ep.SecurityMode} {ep.SecurityPolicyUri}");

// 找最强加密 endpoint
var best = endpoints.Where(e => e.SecurityMode == MessageSecurityMode.SignAndEncrypt)
.OrderByDescending(e => e.SecurityLevel).FirstOrDefault();

8. 加密连接 (Sign / SignAndEncrypt)

using var ua = new DarraOpcUa("opc.tcp://server:4840",
securityMode: MessageSecurityMode.SignAndEncrypt,
securityPolicyUri: "http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256",
clientCertPath: @"C:\certs\my_client.pfx",
clientKeyPath: "pfx_password");
ua.Connect();
// 内部走 OPN(SignAndEncrypt) + RSA-OAEP-SHA1 + AES-256-CBC + HMAC-SHA256

// 用户名 / 证书 UserToken
using var ua2 = new DarraOpcUa("opc.tcp://server:4840",
username: "admin", password: "secret");

9. 事件订阅 (Events 集合)

ua.Events.Connected += (s, e) => Console.WriteLine($"✓ {e.EndpointUrl}");
ua.Events.Disconnected += (s, e) => Console.WriteLine($"✗ {e.StatusCode}");
ua.Events.Reconnecting += (s, e) => Console.WriteLine("正在重连...");
ua.Events.KeepAlive += (s, e) => Console.WriteLine($"心跳: {e.ServerTimeUtc}");
ua.Events.CommunicationError += (s, e) => Console.WriteLine($"通讯错误: {e.Message}");
ua.Events.Any += (s, e) => // 统一通道, 收所有事件
Console.WriteLine($"[{e.Category}] [{e.Severity}] {e.Message}");

10. C# 易错点 (AI 生成代码常踩的坑)

理由
var dv = ua.Read("i=2258"); ...using var dv = ua.Read("i=2258"); ...DataValue 持有 native handle, 必须 Dispose
if (dv.Status == 0) ...if (dv.IsGood) ...if (dv.Status == StatusCode.Good)用枚举/属性, 不要直接比 0
var v = new Variant(42);var v = new Variant(); v.SetInt32(42);SDK 用显式 setter, 避免类型推断误判
没 try/catch包裹 try { ... } catch (OpcUaException ex) { ... }网络/协议错误统一 OpcUaException
sub.Start(); (不存在)sub = ua.CreateSubscription(500); sub.Add("...")AutoPublish 默认开, 自动启动
回调里直接更新 UIInvoke(() => UpdateUI(...))回调在非 UI 线程, WinForms/WPF 必须 Invoke
ua.Call("ns=2;s=Add", 3, 5); (缺 ObjectNodeId)ua.Call("ns=2;s=ParentObject", "ns=2;s=Add", v3, v5)Method Call 需要 (ObjectNodeId, MethodNodeId) 二元组

11. 完整 Demo (Connect + Browse + Subscribe + 优雅退出)

using DarraOpcUa_Client;

class Program
{
static async Task Main()
{
using var ua = new DarraOpcUa("opc.tcp://localhost:4840");
ua.Events.Connected += (s, e) => Console.WriteLine($"已连接 {e.EndpointUrl}");
ua.Events.Disconnected += (s, e) => Console.WriteLine("已断开");

try
{
ua.Connect();

// 列命名空间
for (int i = 0; i < ua.Namespaces.Count; i++)
Console.WriteLine($"ns={i}: {ua.Namespaces[i]}");

// 浏览根
foreach (var r in ua.Browse("i=85"))
Console.WriteLine($" {r.NodeId,-20} [{r.NodeClass}]");

// 订阅 ServerStatus.CurrentTime
using var sub = ua.CreateSubscription(500);
sub.DataChanged += (s, e) =>
Console.WriteLine($"⏰ {e.NodeId} = {e.ValueString}");
sub.Add(WellKnownNodes.Server_ServerStatus_CurrentTime);

Console.WriteLine("收 5 秒数据后退出...");
await Task.Delay(5000);
}
catch (OpcUaException ex)
{
Console.WriteLine($"❌ {ex.StatusCode}: {ex.Message}");
}
}
}

12. WellKnownNodes (内置常量)

常量NodeId
WellKnownNodes.Serveri=2253
WellKnownNodes.Server_ServerStatusi=2256
WellKnownNodes.Server_ServerStatus_CurrentTimei=2258
WellKnownNodes.Server_ServerStatus_Statei=2259
WellKnownNodes.Server_ServerStatus_BuildInfo_ProductNamei=2261
WellKnownNodes.Server_NamespaceArrayi=2255
WellKnownNodes.ObjectsFolderi=85
WellKnownNodes.RootFolderi=84

13. StatusCode 速查 (常见错误)

StatusCode含义
StatusCode.Good0x00000000成功
StatusCode.BadCommunicationError0x80050000网络通讯失败
StatusCode.BadConnectionRejected0x80AC0000server 拒绝
StatusCode.BadCertificateInvalid0x80120000证书无效
StatusCode.BadIdentityTokenRejected0x80210000用户名/证书被拒
StatusCode.BadSessionIdInvalid0x80250000会话已失效
StatusCode.BadNodeIdUnknown0x80340000NodeId 不存在
StatusCode.BadAttributeIdInvalid0x80350000属性不存在
StatusCode.BadNotReadable0x80380000节点不可读
StatusCode.BadNotWritable0x80390000节点不可写
StatusCode.BadServiceUnsupported0x800B0000server 不支持该服务