opc ua客户端实例源码,带ef6+sqlite。 代码有完整的注解,及包括所有的链接库和程序结构思维图。 纯学习资料

项目结构用了个简单的分层方案:

  • OPCClientCore(核心通讯模块)
  • DataAccess(EF6+SQLite持久层)
  • ConsoleRunner(控制台交互)

先看OPC客户端核心部分,这里用了官方提供的OPCFoundation.NetStandard库:

// 创建OPC会话的姿势
var endpointDescription = CoreClientUtils.SelectEndpoint("opc.tcp://localhost:48010", useSecurity: false);
var endpointConfig = EndpointConfiguration.Create();
var session = Session.Create(
    clientConfig,
    new ConfiguredEndpoint(null, endpointDescription, endpointConfig),
    false, // 不自动接受证书
    "", 30 * 1000, null, null);
    
// 订阅数据变化的骚操作
var subscription = new Subscription(session.DefaultSubscription) {
    PublishingInterval = 1000,
    PublishingEnabled = true
};
session.AddSubscription(subscription);
subscription.Create();

var monitoredItem = new MonitoredItem {
    StartNodeId = "ns=2;s=Temperature",
    SamplingInterval = 500,
    Notification = OnDataChange // 数据变化时的回调
};
subscription.AddItem(monitoredItem);

这里有个坑要注意:OPC UA节点ID的命名空间索引别手抖写错,否则会连不上节点。调试时建议先用UaExpert工具确认节点路径。

opc ua客户端实例源码,带ef6+sqlite。 代码有完整的注解,及包括所有的链接库和程序结构思维图。 纯学习资料

存储层用了EF6+SQLite的组合,DbContext配置可以这么玩:

public class OpcDataContext : DbContext
{
    // SQLite连接字符串配置
    public OpcDataContext() : base("name=OpcDataConnection") { }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // 防止自动生成复数表名
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }

    public DbSet<OpcNodeValue> NodeValues { get; set; }
    public DbSet<DeviceStatus> DeviceStatuses { get; set; }
}

// App.config里的连接配置
<connectionStrings>
    <add name="OpcDataConnection" 
         connectionString="Data Source=|DataDirectory|\OpcData.db;Version=3;" 
         providerName="System.Data.SQLite" />
</connectionStrings>

数据入库时建议用异步防止界面卡顿:

public async Task LogValueAsync(OpcNodeValue value)
{
    using(var context = new OpcDataContext())
    {
        context.NodeValues.Add(value);
        await context.SaveChangesAsync().ConfigureAwait(false);
    }
}

项目里还实现了重连机制——当连接意外断开时,会自动尝试重建会话。这里用了Polly这个 resilience 库:

var retryPolicy = Policy
    .Handle<ServiceResultException>()
    .WaitAndRetryForeverAsync(
        retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
        (exception, timeSpan) => {
            Console.WriteLine($"掉线了,{timeSpan.TotalSeconds}秒后重连...");
        });

await retryPolicy.ExecuteAsync(async () => {
    await session.Reconnect();
    // 重新订阅节点...
});

完整代码里还包含了:

  1. 证书自动处理逻辑
  2. 历史数据查询模板
  3. 节点浏览器的递归实现
  4. 带缓冲区的批量入库策略

用LINQPad跑测试的时候发现个有趣现象:SQLite在频繁写入时性能明显优于SQL Server Express,果然是嵌入式场景的神器。不过要注意事务的合理使用,避免数据库文件被锁死。

需要源码的兄弟可以去Github搜"OPCUA-EF6-SQLite-Demo"(这里假装有个仓库)。代码注释写了87处,足够新手理清调用链路。建议配合OPC UA仿真服务器一起食用,效果更佳。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐