Files
UA-.NETStandard/docs/migrate/2.0.x/pubsub.md
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

10 KiB

PubSub (Part 14)

When to read this: Read this if your application uses any of the Opc.Ua.PubSub.* namespaces, the legacy UaPubSubApplication factory, the JsonEncodingMode enum, or RawData field encoding. This sub-doc documents the PubSub breaking and behaviour-affecting changes in 2.0.

For the full Part 14 feature reference, including additive 2.0 capabilities, see PubSub.md. This sub-doc focuses on migration work required for existing consumers.

Contents

1. PubSub assemblies and NuGet packages renamed and split

The monolithic 1.5.378 PubSub library has been refactored into one core assembly plus dedicated transport and server-integration assemblies. Each assembly ships as its own NuGet package under the OPCFoundation.NetStandard.Opc.Ua.PubSub* package prefix:

Assembly NuGet package Contents
Opc.Ua.PubSub OPCFoundation.NetStandard.Opc.Ua.PubSub Core application, encoding, scheduling, security, and DataSets.
Opc.Ua.PubSub.Udp OPCFoundation.NetStandard.Opc.Ua.PubSub.Udp UDP datagram transport (Part 14 §7.3.2).
Opc.Ua.PubSub.Eth OPCFoundation.NetStandard.Opc.Ua.PubSub.Eth Ethernet Layer 2 transport (opc.eth://, EtherType 0xB62C).
Opc.Ua.PubSub.Mqtt OPCFoundation.NetStandard.Opc.Ua.PubSub.Mqtt MQTT broker transport (Part 14 §7.3.4).
Opc.Ua.PubSub.Server OPCFoundation.NetStandard.Opc.Ua.PubSub.Server Server-side address-space integration (Part 14 §9).
Opc.Ua.PubSub.Adapter OPCFoundation.NetStandard.Opc.Ua.PubSub.Adapter External-server publisher/subscriber/Action binding over ManagedSession.

Consumers that previously referenced the single Opc.Ua.PubSub package must add the transport package(s) they use (...PubSub.Udp and/or ...PubSub.Mqtt) and, for address-space integration, the ...PubSub.Server package. Add ...PubSub.Adapter when a PubSub application must bind DataSets or Actions to an external OPC UA server through a managed client session. The root namespaces follow the assembly names (Opc.Ua.PubSub, Opc.Ua.PubSub.Udp, Opc.Ua.PubSub.Mqtt, Opc.Ua.PubSub.Server).

The legacy 1.04 top-level types listed in §2 are removed in 2.0. The sole bridge retained in the main PubSub assembly is the obsolete IUaPubSubDataStore interface. Existing application, connection, publisher, and configurator code must migrate to the modern fluent builder / DI surface.

2. UaPubSubApplication.Create* and the legacy 1.04 API are replaced

UaPubSubApplication.Create(...) (and its overloads) and the legacy 1.04 application, connection, publisher, and configurator types are removed in 2.0. There is no Opc.Ua.PubSub.Legacy compatibility package. Migrate those sites to the fluent builder or the DI extensions:

Removed legacy type New replacement
UaPubSubApplication IPubSubApplication (built via PubSubApplicationBuilder)
IUaPubSubConnection IPubSubConnection
UaPubSubConnection PubSubConnection (sealed runtime implementation, normally created by the builder)
IUaPublisher / UaPublisher IPubSubScheduler + WriterGroup (engine-driven)
UaPubSubConfigurator PubSubApplicationBuilder (fluent) + IPubSubConfigurationStore
PubSubJsonEncoder / PubSubJsonDecoder Opc.Ua.PubSub.Encoding.Json.JsonEncoder / JsonDecoder (System.Text.Json)

IUaPubSubDataStore remains in Opc.Ua.PubSub (marked [Obsolete], UA0023) because the modern bridge still consumes it; migrate to IPublishedDataSetSource (per-DataSet provider model) when convenient.

Codemod recipe:

// Before (1.5.378)
var app = UaPubSubApplication.Create("publisher.xml");
app.Start();
// ...
app.Stop();

// After (2.0)
ITelemetryContext telemetry = DefaultTelemetry.Create(
    logging => logging.AddConsole());
var builder = new PubSubApplicationBuilder(telemetry)
    .UseConfigurationFile("publisher.xml");
await using IPubSubApplication app = await builder.BuildAndStartAsync();
// ...
await app.StopAsync();

See PubSub.md §Fluent builder for the in-code form. Cites Part 14 §6.2.

3. JSON encoder switched to System.Text.Json

The Newtonsoft-based encoder (Opc.Ua.PubSub.Encoding.JsonNetworkMessage v1) is replaced with a System.Text.Json-backed encoder under src/Opc.Ua.PubSub/Encoding/Json/. Behaviour changes that may surface in callers:

  • The Newtonsoft.Json dependency is dropped. Core does not supply it either; add an explicit reference if application code still uses Newtonsoft APIs. See package dependency migration.
  • Numeric round-trips honour the .NET native precision instead of the Newtonsoft default (e.g. double → 17 significant digits, not 15).
  • The new encoder is Utf8JsonWriter-backed; allocations on the hot path drop ~70 % vs. the Newtonsoft pipeline.
  • The decoder uses Utf8JsonReader and validates structurally; it rejects trailing junk where the old decoder silently truncated.

4. JsonEncodingMode Reversible/Non-Reversible encodings removed

Opc.Ua.PubSub.Encoding.Json.JsonEncodingMode.Reversible and Opc.Ua.PubSub.Encoding.Json.JsonEncodingMode.NonReversible are removed in favour of the Part 6 §5.4.1 / Part 14 §7.2.5 names:

Old New
JsonEncodingMode.Reversible JsonEncodingMode.Verbose
JsonEncodingMode.NonReversible JsonEncodingMode.Compact
(new) JsonEncodingMode.RawData

Verbose carries the same information as the old Reversible mode, and Compact the same as NonReversible; the rename is a public-API change. Note the encoder switch to System.Text.Json (§3) can change incidental formatting (e.g. number precision), so output is not guaranteed byte-identical to the 1.04 Newtonsoft encoder. No [Obsolete] aliases exist — consumers update enum references at upgrade time. Background: #3609.

5. UADP RawData bounded-field wire-compatibility break

This is an on-wire compatibility break for consumers of bounded RawData fields. Per Part 14 §7.2.4.5.11, String, ByteString, XmlElement, and array fields encoded via DataSetFieldContentMask.RawData are now padded to the maximum size declared in FieldMetaData.MaxStringLength or FieldMetaData.ArrayDimensions. The on-wire length prefix is suppressed for padded fields; consumers receive the exact MaxStringLength bytes with trailing NULs as the spec mandates, and decoders trim the trailing NUL fill on read.

If your configuration uses RawData but does not declare MaxStringLength or ArrayDimensions, the encoder falls back to the legacy length-prefixed form (variable size) and the configuration validator surfaces issue code PSC0025 (SpecClause = "7.2.4.5.11") so the missing bound is reported at configuration time. Closes #3566.

6. Compatibility matrix

Surface 2.0 outcome
UaPubSubApplication.Create(string) from XML config Source break. Replace with PubSubApplicationBuilder.UseConfigurationFile(...) and BuildAndStartAsync().
UaPubSubApplication.Start() / .Stop() Source break. Use IPubSubApplication async lifecycle methods.
Direct construction of UaPubSubConnection etc. Source break. Configure connections through the fluent builder / DI surface.
IUaPubSubDataStore Compiles with [Obsolete]; PubSubApplicationBuilder.WithDataStore(...) adapts it temporarily. Migrate to IPublishedDataSetSource.
Newtonsoft-based PubSub JSON formatting assumptions Behavioural break. System.Text.Json precision and validation rules apply.
JsonEncodingMode.Reversible / NonReversible Source break. Rename to Verbose / Compact.
DataSetFieldContentMask.RawData with bounded strings/arrays Wire break. Fields are padded and length prefixes suppressed per spec.

See also