Files
UA-.NETStandard/docs/Concepts.md
5899354441 Clarify documentation, migration guidance, and SDK selection (#4823)
# Description

Remove stock phrasing and correct misleading or inconsistent technical
documentation. The initial two passes covered 367 Markdown files,
followed by an interactive review of 169 editorial flags. The U5
interpretation originally deferred in that review has since received the
upstream Mantis answer recorded by #4843; remaining server/spec
follow-ups stay explicit in the CTT log.

- Correct package responsibilities, migration steps, API names,
ownership, protocol descriptions and links. Keep bundled migration
guides synchronized. Preserve historical conclusions as historical
records with separate re-check notes.
- Provide at least two rendered TOC levels throughout `docs/`. Convert
appropriate architecture figures to Mermaid without changing code
examples, transcripts or historical quotations.
- Address the October 19 feedback with concrete setup/migration
instructions, corrected certificate paths and PubSub names, shorter
repeated caveats, consistent XML comments, and a full review of the
Concepts guide. Retain #4839's API corrections.
- Integrate #4841's runtime/performance guidance and review
incoming/recent prose. Preserve dated measurements rather than claiming
new benchmark runs; clarify allocation ratios, startup-only processor
settings, JIT warm-up and the benchmark commit's scope. Missing raw
measurement artifacts and repeat ranges remain tracked by #4842.
- Merge master through `e8c5d800a` in `32c6394b7`. Resolve the CTT log
conflict using the updated Mantis states and OPC answers, retaining
historical framing and re-checks for C28/C32/C43.
- Address the latest naming/index feedback in `adb5bf693`: rename the
guides to `docs/WotCon.md` and `docs/WotNodeSetConversion.md`; move the
provider and DataType-declaration contracts into the conversion guide
and remove `docs/WoT.md`. Rename `samples/DI` to `samples/Di` and
`samples/Isa95` to `samples/ISA95`. Add content-index READMEs to Di,
FluentApi, ISA95, Lds and PubSub; update solution entries, project
references, Docker/CI paths, test fixture paths and documentation links
with exact casing.

**WoT guide scope.** This branch retains the detailed conversion guide
that #4758 had replaced with an anchor stub. Conversion limits, verified
document sets, preservation rules and provider ownership now live
together in `WotNodeSetConversion.md`; binding/runtime guidance remains
in `WotBindings.md` and `WotCon.md`. The design-rationale/test-ledger
prose was shortened, the oversized argument-table cell moved into its
section, and existing anchors preserved.

**SDK policy is a separate, explicit user-directed change.**
`global.json` sets a stable minimum of `10.0.400`, `rollForward:
latestMajor`, and `allowPrerelease: false`. Newer major SDKs are
permitted; CI's explicit SDK pins are unchanged. README, GettingStarted,
DeveloperGuide and Recycling instructions reflect the possible analyzer
differences. The image-contract regression fix accepts compatible stable
SDK images instead of requiring exact equality with the floor.

The latest four rename/index threads are resolved after publication.
Three older threads remain open: universal obsolete-removal timing,
unconditional nonce-strength wording, and a blanket Vision NativeAOT
claim. Existing implementation/evidence constraints are explained in
their inline replies. The two-level TOCs remain as requested.

## Validation

- `git diff --check` and staged diff checks: passed. The untouched
upstream AutoID NodeSet retains its provenance bytes, including two
existing license-header trailing spaces.
- `.\.azurepipelines\validate-migration-plugin.ps1`: passed; 15 bundled
migration documents and manifests synchronized.
- Documentation/path validation: **101** documents retain two rendered
TOC levels (**2,228** entries), with idempotent formatting. **52** new
relative links and their anchors passed exact-case checks. No tracked
references to the old guide/sample paths remain. Both relocated
provider-contract sections are preserved in the destination.
- `dotnet sln UA.slnx list`: passed; shows the renamed Di/ISA95 projects
and the existing FluentApi/Lds/PubSub projects. Updated solution and
pump ProjectReference paths also passed exact-case existence checks.
- Latest focused commands, run from the repository root:

```powershell
# Passed: 61 channel send-order and reconnect tests.
dotnet test tests\Opc.Ua.Core.Tests\Opc.Ua.Core.Tests.csproj -p:CustomTestTarget=net10.0 --filter 'FullyQualifiedName~UaSCBinaryChannelSendOrderTests|FullyQualifiedName~TcpReconnectKeyAgreementTests' --verbosity minimal

# Passed: 5 pump datasheet tests; builds the renamed pump sample.
dotnet test tests\Opc.Ua.Di.Tests\Opc.Ua.Di.Tests.csproj -p:CustomTestTarget=net10.0 --filter 'FullyQualifiedName~PumpDatasheetConformanceTests' --verbosity minimal

# Passed: 4 repository NodeSet path/round-trip tests, including the moved pump models.
dotnet test tests\Opc.Ua.Types.Tests\Opc.Ua.Types.Tests.csproj -p:CustomTestTarget=net10.0 --filter 'FullyQualifiedName~RepositorySourceSurvivesSerializedLinkedPartitionsAsync' --verbosity minimal

# Passed: build, zero warnings/errors.
dotnet build samples\ISA95\MinimalIsa95Server\MinimalIsa95Server.csproj -p:CustomTestTarget=net10.0 -f net10.0 --verbosity minimal

# Passed: dependent sample-test project build, zero warnings/errors.
dotnet build tests\Opc.Ua.WotCon.Samples.Tests\Opc.Ua.WotCon.Samples.Tests.csproj -p:CustomTestTarget=net10.0 -f net10.0 --verbosity minimal
```

Earlier focused integration checks passed 2,620 tests across AutoID,
event queues/scheduling, source generation, MCP/package profiles and
WoT. Both reviewed Mermaid diagrams rendered locally without network
access. These checks are not a full solution run.

The full solution has **not** been rerun for this review. Earlier
`dotnet test UA.slnx -p:CustomTestTarget=net10.0 --verbosity quiet` did
not pass: three AOT projects rejected VSTest and 20 Vision tests failed
during graphics initialization with `OutOfMemoryException`. Remaining
long-running tests were stopped at the user's request. A focused Vision
rerun passed 558 tests and reproduced those 20 failures. The earlier
`dotnet test UA.slnx -p:CustomTestTarget=net48 --verbosity quiet` was
blocked by the former SDK pin and was not retried after the policy
change. The user approved proceeding with those limitations documented;
current remote CI is not claimed green.

## Related Issues

- Follow-up #4842 tracks the requested 2.0.2+ benchmark/tuning and
diagnostic-tool documentation refresh. #4841 supplies documentation and
earlier results, not all newly requested measurements.
- #4758 explains the conversion guide's earlier consolidation; the
current provider contracts are now consolidated into
`WotNodeSetConversion.md`.
- #4839 supplies the reviewed API corrections; #4843 supplies the
updated CTT issue record.
- The original prose cleanup and SDK policy were user-requested without
a source issue. No new runtime architecture is introduced by these
documentation edits.

## Checklist

_Put an `x` in the boxes that apply. You can complete these step by step
after opening the PR._

- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [ ] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [x] I have added all necessary documentation.
- [ ] I have verified that my changes do not introduce (new) build or
analyzer warnings.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [ ] I have addressed **all** PR feedback received.

---------

Co-authored-by: Roman Ettlinger <romanett98@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 10:10:55 +02: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 ApplicationUri, which identifies that installed instance. An application instance certificate authenticates the instance when certificate-based security is used; its URI must match the ApplicationUri. 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 default hosting setup can create a missing application certificate. A custom certificate manager can instead require provisioning before startup.

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 Protects messages according to the selected transport, security mode and policy; None provides no UA message signing or encryption. Application instance certificates when the selected security profile uses them.
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, provide browse paths through the graph; a node can have more than one parent. 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 when notifications are ready for pending Publish requests.
  2. The client adds monitored items. Each one watches a node attribute, usually a variable's value, or an event source. For data changes, the sampling interval controls how often the server checks the value; events are reported when they occur. The queue size controls how many notifications it retains.
  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 Transport/channel security plus per-session user identity. Optional message security with group keys, which a Security Key Service can distribute; transport security depends on the mapping.
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.