Files
Marc Schier c4e0721a29 Add a documentation learning path and fix issues found while verifying it (#4555)
## Summary

### Documentation
- Stage the documentation index as a learning path: a first application,
independent client, server, and PubSub paths, then data and services,
companion models, production, advanced integration, and draft or
experimental capabilities.
- Add Getting started (repository samples or NuGet packages), OPC UA
concepts, Your first information model, and a production readiness
checklist.
- Add Native AOT application publishing, a first PubSub publisher and
subscriber exchange, and the UDP transport options.
- Add or expand contents navigation throughout `docs/`, and keep
contributor documentation separate.
- Correct outdated SDK examples and capability guidance, consolidate
repeated explanations into canonical guides, and repair local links and
heading structure.
- Rewrite What's New in 2.0 as a concise feature overview with short
linked details; keep migration instructions in the Migration Guide.
- Expand the feature catalogue with specification IDs, GDS, LDS, the OPC
10000-21 onboarding registrar, ISA-95, xRegistry, OpenUSD, and
sample-local models; distinguish draft status, explain crypto
pluggability, and bring performance guidance forward.
- Address review feedback on wording, active monitored items during
shadow reload, and the `Samples.md` filename and references.
- Regenerate the `opcua-v20-migration` plugin's bundled copy of the
migration guides so it matches the edited `docs/migrate/2.0.x` guides.
- Merge the latest `master`, preserving upstream resource-isolation
guidance within the task-based documentation index.
- Retain deferred Lingity findings where appropriate; this PR does not
claim that every document meets the Lingity score thresholds.

### Fixes found while verifying the guides
Each fix has regression tests that fail without it.
- **Client:** V2 subscriptions compared their lifetime with the
operation timeout instead of the session timeout, and logged a spurious
warning. `ISubscriptionEngineContext`, which is new in 2.0, gains a
`SessionTimeout` property; implementations must add it.
- **PubSub:** a subscriber now registers the `DataSetMetaData`
configured on its readers (OPC 10000-14 6.2.9.4), and the UADP decoder
decodes DataSetMessages that carry no ConfigurationVersion. Before, a
secured subscriber of the reference sample received no DataSets.
- **Source generator:** a ModelDesign method that declares its arguments
inline, without a method type, produced code that did not compile; it
now uses `MethodState`. The generated code of existing models is
unchanged.
- **MinimalClient sample:** waits for its first data-change notification
before it disconnects.

### Known issues, not addressed here
- UDP multicast: the publisher does not send on the interface that the
subscriber joins, and `MulticastLoopback` defaults to false. The PubSub
guide uses unicast for the exchange on one computer.
- The UDP metadata announcement is sent unsecured on secured writer
groups; a secured subscriber drops it with a warning.
- A server does not start in globalization-invariant mode, because
`ResourceManager` creates `CultureInfo("en-US")`. The Native AOT guide
cautions against the mode.

## Validation
- `git diff --check` and
`./.azurepipelines/validate-migration-plugin.ps1` (15 bundled migration
docs validated, plugin manifests synchronized).
- Local Markdown links, anchors, file-link casing, and contents lists
checked across all 87 documents under `docs/`. The index links every
top-level guide and every target of the previous index.
- Both Getting started routes, Your first information model, the PubSub
exchange, and the Native AOT publish of the Getting started client and
server were run as documented. The NuGet route and the tutorial use the
public `2.0.0-preview.5` packages.
- The changed libraries build for all target frameworks in Release
without warnings.
- Tests on .NET 10: Opc.Ua.SourceGeneration.Tests 199 passed;
Opc.Ua.SourceGeneration.Core.Tests 3,977 passed, 8 skipped;
Opc.Ua.Server.Tests `Fluent` category 621 passed; Opc.Ua.Client.Tests
subscription-engine tests 70 passed; Opc.Ua.PubSub.Tests 1,374 passed, 2
skipped; PubSub fuzz replay 145 passed. The new and affected tests also
pass on .NET Framework 4.8.
- Earlier merge validation: 174 resource-isolation tests passed on .NET
10.
- The full solution suite was not run locally.

Review and validation artifacts are maintained outside the repository.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-09-28 19:19:39 +00:00

13 KiB

OPC UA concepts for SDK users

This guide explains the ideas the rest of the documentation assumes. Read it alongside Getting started or immediately afterward. It describes the concepts and the matching SDK types without detailing each API. Each section links to the guide with complete contracts and examples.

Contents

Applications

An OPC UA application is a client, a server, or both. Each application instance has an application instance certificate and an ApplicationUri. The URI identifies that installed instance and must match the URI in its certificate. A product URI identifies the product rather than one installation.

In this SDK, you set the application name, URIs, and certificate-store root when you configure a client or server. The hosting builders create the application certificate on first start if the store does not contain one.

Endpoints, secure channels, and sessions

A server offers one or more endpoints. An endpoint combines:

  • A URL, such as opc.tcp://localhost:62541/MinimalBoilerServer.
  • A transport, such as UA-TCP (opc.tcp), HTTPS, or WebSockets.
  • A security mode: None, Sign, or SignAndEncrypt.
  • A security policy, such as Basic256Sha256, which selects the algorithms.
  • The user-token types the server accepts.

A client usually calls the discovery service GetEndpoints and selects the endpoint whose security matches its requirements. The client then establishes two layers:

Layer Purpose Authenticated by
Secure channel Signs and encrypts the messages between the two application instances. Application instance certificates.
Session Carries the user identity, request context, and subscriptions. A user token, such as anonymous, user name, X.509, or an issued token.

A session can survive the loss of its channel: the client opens a new channel and reactivates the same session. ManagedSession performs this recovery and, if necessary, recreates the session. It is the recommended client entry point for new applications. See Sessions and Transports.

Application trust and user identity

Application trust and user identity are separate decisions:

  • Application trust decides whether this software instance may open a secure channel. Each application keeps certificate stores: its own certificates, trusted peers, issuers needed to validate chains, and rejected certificates. An administrator approves a peer by placing its certificate, or the CA that issued it, in the trusted store.
  • User identity decides who is using the session and what that user may do. The server authenticates the user token when the session is activated and maps the identity to roles and permissions.

Accepting unknown certificates automatically is a local-testing shortcut only; it removes the protection against connecting to, or accepting, an impostor. See Certificates, Identity providers, and Role-based user management.

The address space

A server exposes its data as an address space: a graph of nodes connected by references. Each node has a node class:

Node class Represents
Object A device, machine, or other entity; also folders.
Variable A value that can be read, written, or monitored.
Method An operation that a client can call on an object.
ObjectType, VariableType The definitions that instances are based on.
DataType, ReferenceType The definitions of value types and relationship types.
View A subset of the address space.

References have types. Hierarchical references, such as Organizes, HasComponent, and HasProperty, form the tree you browse. Other references describe relationships, such as HasTypeDefinition, which links an instance to its type. Every server has a standard Objects folder (ObjectIds.ObjectsFolder) that contains the Server object with status, capabilities, and diagnostics.

A server-side node manager owns part of the address space and implements its behavior. See Node managers.

Node identity and namespaces

A NodeId combines a namespace index with an identifier, which is a number, a string, a GUID, or an opaque byte string. The index refers to an entry in the server's namespace table (NamespaceArray), which lists namespace URIs:

  • Index 0 is always the OPC UA namespace, http://opcfoundation.org/UA/.
  • Index 1 is the server's own local namespace.
  • Other indexes are assigned by the server and can differ between servers.

Store and exchange the namespace URI, not the index. Resolve the index from the connected session's namespace table (session.NamespaceUris) when needed. An ExpandedNodeId can carry the URI itself. Generated model constants use this form; convert one with ExpandedNodeId.ToNodeId(id, session.NamespaceUris). Standard node IDs such as VariableIds.Server_ServerStatus_CurrentTime are in namespace 0 and need no conversion.

A node's BrowseName is a QualifiedName: a name with a namespace index. Clients can translate a browse path of names into a NodeId.

NodeId, QualifiedName, Variant, DataValue, and several other built-in types are value types in this SDK. Test them with IsNull rather than comparing them with null. See Improved type safety for details.

Values, status codes, and timestamps

Reading a variable returns a DataValue, which contains four parts:

Part SDK member Meaning
Value WrappedValue (Variant) The value, or no value.
Status StatusCode Whether the value can be used.
Source timestamp SourceTimestamp (DateTimeUtc) When the value was produced at its source.
Server timestamp ServerTimestamp (DateTimeUtc) When the server last received or confirmed the value.

Always check the status before you use the value. A status is Good, Uncertain (usable with caution), or Bad (do not use the value). Use StatusCode.IsGood, StatusCode.IsUncertain, and StatusCode.IsBad, or compare with a constant such as status == StatusCodes.BadNodeIdUnknown.

A Variant holds any OPC UA built-in type, an array (ArrayOf<T>), a matrix (MatrixOf<T>), or a structure (ExtensionObject). Extract a value with the checked TryGetValue pattern:

if (!StatusCode.IsBad(value.StatusCode) &&
    value.WrappedValue.TryGetValue(out DateTimeUtc time))
{
    Console.WriteLine($"{time} ({value.StatusCode})");
}

All OPC UA date and time values are UTC and use DateTimeUtc. Binary data uses ByteString. Server-defined structures can be decoded at run time with Complex types, or compiled with Source-generated data types.

Service results and errors

Clients call services, such as Read, Write, Browse, and Call. Most services process a list of operations and return one result per operation, so one failed item does not fail the whole call. Check each result's status.

A failure of the whole request, such as a timeout or a security error, raises a ServiceResultException. Its StatusCode identifies the cause. Convenience helpers can convert a Bad operation result into an exception; for example, ReadValueAsync throws when the value's status is Bad.

Subscriptions and monitored items

Polling with Read is inefficient for values that change. A subscription lets the server report changes instead:

  1. The client creates a subscription in its session. The publishing interval controls how often the server sends notifications.
  2. The client adds monitored items. Each one watches a node attribute, usually a variable's value, or an event source. The sampling interval controls how often the server checks for changes; the queue size controls how many changes it keeps between notifications.
  3. The server sends data-change or event notifications, and keep-alive messages when nothing has changed. If the client stops requesting notifications, the subscription expires after its lifetime.

The SDK offers callback subscriptions for long-lived application monitoring and IAsyncEnumerable streams for short observations, such as waiting for a state change. See Subscriptions.

Events and alarms

Objects that are event notifiers report events, such as audit events or state changes. A client subscribes to them with an event filter that selects the event fields and types it needs. Alarms and conditions extend events with state that operators acknowledge, confirm, or shelve. See Alarms and conditions.

Information models and companion specifications

An information model is a set of types and instances for a domain. The base OPC UA model defines the server object, core types, and standard services. Companion specifications build domain models on top of it, such as Device Integration (OPC 10000-100) or Machinery (OPC 40001-1).

Models are exchanged as NodeSet2 XML files. This SDK can use a model in two ways:

  • Generate typed code at build time, including a server node manager and typed client proxies for object types. See Node managers.
  • Load NodeSet2 files into a running server without generated code. See Runtime NodeSets.

Models depend on other models; for example, Device Integration depends on the base model. See Model dependencies.

Client/server and PubSub

OPC UA defines two communication patterns:

Client/server PubSub
Connection A session between one client and one server. No session; publishers send messages to a transport.
Interaction Requests (read, write, browse, call) and subscriptions. One-way dataset messages, plus optional actions.
Security Secure channel plus per-session user identity. Message security with group keys from a Security Key Service.
Transports UA-TCP, HTTPS, WebSockets. UDP, MQTT, Kafka, Ethernet.

In PubSub, a publisher's DataSetWriter turns a published dataset into dataset messages, and a WriterGroup sends them in network messages at a configured interval over a PubSubConnection. A subscriber's DataSetReader selects messages by publisher, writer group, and dataset writer identifiers, and decodes them with the dataset metadata. Messages use UADP (binary) or JSON encoding. PubSub applications do not need a client or server. See PubSub.

How the SDK is organized

  • Packages. Start with OPCFoundation.NetStandard.Opc.Ua.Client or OPCFoundation.NetStandard.Opc.Ua.Server. Optional packages add transports, complex types, PubSub, redundancy, and companion models. See Packages, platform support, and versioning.
  • Hosting. services.AddOpcUa() registers clients, servers, and features with .NET dependency injection and the Generic Host. Direct construction, such as ManagedSessionBuilder or new StandardServer(telemetry), remains available. See Dependency injection. In this documentation, dependency injection refers to the .NET pattern, while DI in Device Integration refers to OPC 10000-100.
  • Asynchronous APIs. Operations are asynchronous and accept a CancellationToken. Await them; do not block on their results.
  • Telemetry. Components obtain loggers, metrics, and traces from an ITelemetryContext. With hosting, the SDK adapts the host's logging. See Diagnostics.
  • Ownership. Dispose sessions, subscriptions, and certificate handles that you create. ManagedSession and subscriptions support await using.

Where to go next

Return to the documentation index and follow the path for your role: a client, a server, or a PubSub application. If you have not yet run a client and server, start with Getting started. To add your own model to a server and use it from a client, continue with Your first information model.