Potapich.OpcUaNetStandart 1.2.1

dotnet add package Potapich.OpcUaNetStandart --version 1.2.1
                    
NuGet\Install-Package Potapich.OpcUaNetStandart -Version 1.2.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Potapich.OpcUaNetStandart" Version="1.2.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Potapich.OpcUaNetStandart" Version="1.2.1" />
                    
Directory.Packages.props
<PackageReference Include="Potapich.OpcUaNetStandart" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Potapich.OpcUaNetStandart --version 1.2.1
                    
#r "nuget: Potapich.OpcUaNetStandart, 1.2.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Potapich.OpcUaNetStandart@1.2.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Potapich.OpcUaNetStandart&version=1.2.1
                    
Install as a Cake Addin
#tool nuget:?package=Potapich.OpcUaNetStandart&version=1.2.1
                    
Install as a Cake Tool

Tests Coverage License NuGet

Potapich.OpcUaNetStandard

High-performance OPC UA client library for .NET with event-driven architecture, dependency injection support, and flexible subscription management.

Origins & Background

This library has an interesting origin story. For many years, I relied on Kepware's ClientAce libraries for OPC UA connectivity. I must give credit where it's due - their package served us reliably and performed without issues through countless production deployments. However, as with any commercial solution, licensing costs were a consideration, and when our licenses were approaching expiration, I began evaluating alternatives.

I wondered if the open-source ecosystem had matured enough to provide viable OPC UA solutions since I last evaluated options years ago. To my pleasant surprise, I discovered the excellent OPCFoundation.NetStandard.Opc.Ua.Client package from the OPC Foundation team - a robust, well-maintained open-source implementation that met our core requirements.

Around the same time, I had been developing and publishing my own event channel implementation Potapich.EventFlowChannel which provided a clean abstraction for message processing pipelines. The idea emerged to combine these two components: leveraging the solid OPC Foundation client for the protocol implementation while using my event channel package to manage the subscription.

Why Event Channels? For those skeptical about the channel-based approach, consider these advantages:

Traditional OPC UA clients typically use callback mechanisms where:

  • Notification handlers run on I/O threads, potentially blocking communication
  • Limited control over threading and resource utilization
  • Difficult to implement backpressure and flow control
  • Complex error handling and recovery scenarios

The channel-based architecture provides:

  • Built-in concurrency management: Separate readers/writers with configurable parallelism
  • Decoupled processing: I/O operations separated from business logic
  • Backpressure support: Automatic flow control when consumers can't keep up
  • Resource management: Controlled memory usage with bounded channels
  • Fault isolation: Errors in one handler don't crash the entire client
  • Enhanced observability: Clear pipeline for monitoring and diagnostics

The event channel acts as a managed message queue that sits between the OPC UA layer and your application logic, providing a buffer that absorbs bursts of data and allows for controlled, predictable processing.

The result is this integrated solution that maintains the reliability we needed while offering modern .NET patterns, dependency injection support, and a more flexible architecture. If you're facing similar challenges with commercial OPC licensing or simply prefer open-source solutions, this package might provide the alternative you're looking for.

Dependencies

Package Purpose
Potapich.EventFlowChannel Event channel implementation for async event pipelines
OPCFoundation.NetStandard.Opc.Ua.Client Official OPC UA client implementation

Key Features

  • Event-Driven Architecture – Dispatcher pattern for OPC UA subscriptions
  • Multi-Platform Support – Compatible with .NET Standard 2.0 through .NET 9
  • Dependency Injection Ready – Seamless integration with Microsoft.Extensions.DependencyInjection
  • Advanced Subscription Management – Multiple callbacks per monitored item
  • Automatic Session Recovery – Reconnection and keep-alive mechanisms
  • Thread-Safe Operations – Safe concurrent subscription and callback handling
  • Browse Server - Browse OPC nodes hierarchy

Best Practices

  • Session Reuse: Reuse sessions for the same endpoint whenever possible
  • Callback Management: Always unregister callbacks when no longer needed
  • Error Handling: Implement robust error handling in your callbacks
  • Resource Cleanup: Properly dispose of sessions when shutting down

Architecture Overview

graph TD

    Handlers[Handlers.dll]
    Events[Events.dll]
    OpcSessions[OpcSessions.dll]
    OpcSubscriptions[OpcSubscriptions.dll]
    OpcSessionFactory[OpcSessionFactory.dll]
    OpcConfigFactory[OpcConfigFactory.dll]
    OpcCallbacks[OpcCallbacks.dll]

    Handlers --> Events
    Handlers --> OpcSessions
    Handlers --> OpcSubscriptions
    OpcSessions --> OpcSessionFactory
    OpcSessionFactory --> OpcConfigFactory
    OpcSubscriptions --> OpcCallbacks

Event Dispatcher Pattern

Three main event types drive the system:

  • RegisterSession – Establishes a new OPC UA session
  • AddItemToSubscription – Adds a monitored item to a subscription
  • RemoveItemFromSubscription – Removes a monitored item from a subscription

Core Components

  • OpcSessionsManager – Manages OPC UA session lifecycle
  • OpcSubscriptionsManager – Handles subscriptions and monitored items
  • OpcCallbacksManager – Supports multiple callbacks per OPC tag
  • OpcConfigurationManager – Manages client configuration

Installation

<PackageReference Include="Potapich.OpcUaNetStandard" Version="1.0.0" />

Quick Start

Implement Logger

internal class MyLogger : IGenericEventDispatcherLogger
{
    public void LogError(string message) => Console.WriteLine(message);
    public void LogError(string message, Exception exception) => Console.WriteLine($"Error: {exception}");
    public void LogWarning(string message) => Console.WriteLine(message);
}

Configure Services

var provider = new ServiceCollection()
    .AddSingleton<IGenericEventDispatcherLogger, MyLogger>()
    .AddOpcBackend()
    .BuildServiceProvider();

Initialize Channel

var channelBuilder = provider.GetRequiredService<IChannelBuilder<OpcCommandEvent>>();

var opcChannel = channelBuilder
    .Unbounded()
    .WithMultipleWriters()
    .WithReadersCount(1)
    .Build();

opcChannel.Start();

Manage OPC Sessions and Subscriptions

const string endpoint = "opc.tcp://your-server:49320";
const string tagId = "ns=2;s=Your.Tag.Identifier";
const string appId = "your-client-app";

// Create session
await opcChannel.Enqueue(new RegisterSession(appId, endpoint));

// Add subscription with callback
await opcChannel.Enqueue(new AddItemToSubscription(
    appId, 
    tagId, 
    "callback-key", 
    (item, e) => 
    {
        foreach (var value in item.DequeueValues())
            Console.WriteLine($"{DateTime.Now:HH:mm:ss} {item.DisplayName} = {value.Value}");
    }
));

// Remove subscription
await opcChannel.Enqueue(new RemoveItemFromSubscription(appId, tagId, "callback-key"));

Console Output

12:31:02 Your.Tag.Identifier = 42
12:31:03 Your.Tag.Identifier = 43

Get Nodes From OPC Server

///get root level nodes
await opcChannel.Enqueue(new BrowseServer(
    appId,
    null, 
    (node) => {
        Console.WriteLine(
            $"Caption = {node.DisplayName}, " +
            $"FullName = \"{node.FullName}\", " +
            $"Writable = {node.Writable}, " +
            $"IsFolder = {node.IsFolder}");
    }));

///get sub level nodes
await opcChannel.Enqueue(new BrowseServer(
    appId,
    "ns=2;s=Your.Folder.Name", 
    (node) => {
        Console.WriteLine(
            $"Caption = {node.DisplayName}, " +
            $"FullName = \"{node.FullName}\", " +
            $"Writable = {node.Writable}, " +
            $"IsFolder = {node.IsFolder}");
    }));
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.1 175 10/8/2025
1.2.0 178 10/2/2025
1.1.0 171 10/2/2025
1.0.0 149 9/12/2025