Skip to content

Move the samples to preview 2.0.301.4181 and adopt what it added - #879

Merged
romanett merged 2 commits into
masterfrom
romanett/gh-preview-upgrade-d536f2
Sep 8, 2026
Merged

romanett merged 2 commits into
masterfrom
romanett/gh-preview-upgrade-d536f2

Conversation

@romanett

@romanett romanett commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Proposed changes

Moves the samples from 2.0.280.50326-preview (stack commit c4960b54) to
2.0.301.4181-preview (stack commit 105508bc), 21 commits later, and adopts what that
range added.

Breaking changes the bump forces

The GDS packages lost their .Common suffix
(UA-.NETStandard#4438).
OPCFoundation.NetStandard.Opc.Ua.Gds.{Client,Server}.Common are now
…Gds.{Client,Server}, and so are the assemblies inside them — which the GDS sample
applications were already using as their own AssemblyName. MSBuild reported the collision
as MSB3243 and picked a winner at random, not as an error, so the two apps and the
controls library are renamed to Quickstarts.GlobalDiscovery{Client,Server,ClientControls}.
Their RootNamespace and every using are untouched; the sample catalog addresses them by
project path, so nothing else moves.

Part 11 Historical Access was completed
(#4390). Every historian
provider interface changed shape: collections are ArrayOf<T>, an update answers a
HistorianUpdateOutcome<T> (one status per entry plus the values it displaced, for the audit
trail), DeleteRawAsync answers one of those rather than a bare StatusCode,
InsertBatchAsync takes ArrayOf<HistorianDataBatch>, ReadAtTimeAsync answers
ArrayOf<DataValue>, and a resume token carries a ByteString. The three sample providers
follow. On the client, ReadRawAsync and friends gained a HistoryReadNodeOptions
parameter before the cancellation token, so a positional ct no longer compiles.

The fluent configure/seal path became awaitable
(#4442).
NodeManagerBuilder.Configure(…) and Seal() are gone; the two hand-written fluent
managers now run the pipeline the generator emits — CreateFluentBuilder, Configure,
RegisterAuthoredNodesAsync, CompleteConfigureAsync, SealConfigurationAsync.

Patterns adopted

  • Historian capabilities are a gate, not only an advertisement. The dispatcher refuses an
    operation the provider does not claim, and the diagnostics node manager now rolls the event
    flags up as well. WellReportHistorianProvider claims the five event operations it serves,
    TestDataHistorianProvider claims the server timestamps its archive keeps, and
    HistoricalEventsCapabilities no longer sets five flags by hand — only the Server object's
    EventNotifier is left to it.
  • HistorianEventRecord.QualifiedFields is filled from the select clauses beside the flat
    Fields, so two clauses which differ only in their event type no longer collapse onto one
    browse path. The sample's own BuildOperandKey gives way to HistorianEventFieldKey.BuildPath.
  • NodeManagement mints through the NodeId factory
    (#4433) rather than a New
    override, which the AddNodes path no longer reaches — a node built from a TypeDefinition
    arrives carrying the type's id, so the override's !node.NodeId.IsNull guard silently sent
    every request to the base. NodeIdFactory.WithMode(NodeIdAssignmentMode.String) gives the
    sample back the readable identifiers it wanted.
  • RoleManagement stores one wildcard endpoint filter instead of copying every advertised
    endpoint description. AddEndpoint accepts a partial EndpointType now
    (#4412), and Part 18 4.4.2
    says the fields left at their default are ignored anyway — so
    { SecurityMode = SignAndEncrypt } is the whole rule, and it keeps matching when a host
    name is spelled differently.
  • The NodeSet2 InputArguments repair is deleted
    (#4422): the importer binds
    the typed property itself, so BindInputArguments and the README section explaining it are
    gone.

One real bug the bump exposed

DataTypesClientModel called LoadAsync(true, true) on the complex type system, and the
first parameter of that method is onlyEnumTypes. The client built no structured type at
all
, so every structure the server serves arrived as an undecoded extension object — in the
sample whose entire point is that "a value of a structure the client has no compiled knowledge
of arrives decoded into its fields".

Nothing caught it, because the tier 1.7 fixture asserted against WrappedValue.ToString()
and the generated default value used to arrive as the bare XML of the model design
(#4401): the raw text happened
to contain Trek, Cube and 10, so the assertions held on a value that decoded into
nothing. #4414 fixed that generator defect, the body became a binary ByteString, and the
fixture started reporting Byte[35]. Both arguments are named at the call site now.

Recorded issues which paid out

Three KnownIssue wrappers failed because what they recorded now works, and are replaced by
plain assertions: the two structure default values in DataTypesNodeManagerTests (#4401,
fixed by #4414) and the audit trail in RoleManagementNodeManagerTests (fixed by
#4420). The prose describing
those gaps across four READMEs, docs/TESTING.md and three sources is updated.

Two expectations stay ignored because they are still real: a compiled type cannot hand over
its own DataTypeDefinition
(#4424) and no audit event of
an AlarmCondition condition-Method call reaches a subscriber. The second note is narrowed —
the RoleSet Methods of the RoleManagement sample are audited on this stack, so "no audit
event of any type reaches a subscriber" is no longer true.

Related Issues

Nothing to close here. What this bump unblocks or newly exposes is filed rather than crammed
in:

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • Enhancement (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected, requires version increase of Nuget packages)
  • Documentation Update (if none of the other choices apply)

The breaking box is ticked for the GDS assembly renames: anything naming
Opc.Ua.Gds.Client.dll or Opc.Ua.Gds.Server.dll from these sample projects by file name —
a binding redirect, a launch script — has to follow.

Checklist

  • I have read the CONTRIBUTING doc.
  • I have signed the CLA.
  • I ran tests locally with my changes, all passed.
  • I fixed all failing tests in the CI pipelines.
  • I fixed all introduced issues with CodeQL and LGTM.
  • I have added tests that prove my fix is effective or that my feature works and increased code coverage.
  • I have added necessary documentation (if appropriate).
  • Any dependent changes have been merged and published in downstream modules.

Further comments

Validation

UA Samples.slnx builds clean on net48, net8.0 and net10.0. Every tier was run locally on
net10.0:

Tier Result
SampleConfiguration.Tests 237 passed
SampleServers.Tests 121 passed
SampleNodeManagers.Tests 181 passed, 1 skipped
SampleClientModels.Tests 421 passed, 3 skipped
SampleClients.Tests (WinForms) 65 passed

1,025 passed, 0 failed, 4 skipped. The four skips are the recorded known issues named
above plus one pre-existing skip unrelated to this change. The build carries no new warnings,
and the MSB3243 assembly conflict the rename fixes is gone.

On resolving the version

GitHub Packages needs a token with read:packages even for a public feed, which the local
gh token does not carry. The version was resolved and the build validated the way the
repository documentation describes for that situation: from the release-manifest.json of
the last successful nuget-publish.yml run on the stack's master, whose artifact doubles
as a local folder feed. Nothing about that workflow is committed — Nuget.Config is
untouched and targets.props changes only in the pinned version.

🤖 Generated with Claude Code

romanett and others added 2 commits September 8, 2026 19:38
Bumps `OpcUaNetStandardVersion` from `2.0.280.50326-preview` (SDK commit
c4960b54) to `2.0.301.4181-preview` (SDK commit 105508bc), 21 commits later.

## Breaking changes the bump forces

**GDS packages lost their `.Common` suffix** (UA-.NETStandard#4438).
`OPCFoundation.NetStandard.Opc.Ua.Gds.{Client,Server}.Common` are now
`…Gds.{Client,Server}`, and so are the assemblies inside them - which the GDS
sample applications were already using as their own assembly names. MSBuild
reported the collision as MSB3243 and picked a winner at random, so the two
apps and the controls library are renamed to `Quickstarts.GlobalDiscovery*`.
Their namespaces are unchanged.

**Part 11 Historical Access completed** (UA-.NETStandard#4390). Every historian
provider interface changed shape: collections are `ArrayOf<T>`, an update
answers a `HistorianUpdateOutcome<T>` (one status per entry plus the values it
displaced), `DeleteRawAsync` answers one of those rather than a bare status,
`InsertBatchAsync` takes `ArrayOf<HistorianDataBatch>`, `ReadAtTimeAsync`
answers `ArrayOf<DataValue>`, and a resume token carries a `ByteString`. The
three sample providers follow. On the client, `ReadRawAsync` and friends grew a
`HistoryReadNodeOptions` parameter before the cancellation token.

**The fluent configure/seal path became awaitable** (UA-.NETStandard#4442).
`NodeManagerBuilder.Configure(…)` and `Seal()` are gone; the two hand-written
fluent managers now run the pipeline the generator emits - `CreateFluentBuilder`,
`Configure`, `RegisterAuthoredNodesAsync`, `CompleteConfigureAsync`,
`SealConfigurationAsync`.

## Patterns adopted

- **Historian capabilities are a gate, not just an advertisement.** The
  dispatcher refuses an operation the provider does not claim, and the
  diagnostics node manager rolls the event flags up. `WellReportHistorianProvider`
  claims its five event operations, `TestDataHistorianProvider` claims the server
  timestamps its archive keeps, and `HistoricalEventsCapabilities` no longer sets
  five flags by hand - only the Server object's EventNotifier is left to it.
- **`HistorianEventRecord.QualifiedFields`** is filled from the select clauses
  beside the flat `Fields`, so two clauses which differ only in their event type
  no longer collapse onto one browse path. The sample's own `BuildOperandKey`
  gives way to `HistorianEventFieldKey.BuildPath`.
- **NodeManagement mints through the NodeId factory** (UA-.NETStandard#4433)
  rather than a `New` override, which the AddNodes path no longer reaches:
  `NodeIdFactory.WithMode(NodeIdAssignmentMode.String)` gives it the readable
  identifiers it wanted. The other ten samples are tracked in #875.
- **RoleManagement stores one wildcard endpoint filter** instead of copying every
  advertised endpoint description: `AddEndpoint` accepts a partial `EndpointType`
  now (UA-.NETStandard#4412), and Part 18 §4.4.2 says the empty fields are
  ignored anyway.
- **The NodeSet2 `InputArguments` repair is deleted** (UA-.NETStandard#4422): the
  importer binds the typed property itself, so `BindInputArguments` and the
  README section explaining it are gone.

## Recorded issues which paid out

Three `KnownIssue` wrappers failed because what they recorded now works, and are
replaced by plain assertions: the two structure default values in
`DataTypesNodeManagerTests` (#4401, fixed by #4414) and the audit trail in
`RoleManagementNodeManagerTests` (fixed by #4420). The prose which described
those gaps across four READMEs and three sources is updated.

## Validation

`UA Samples.slnx` builds clean on net48/net8.0/net10.0. `SampleNodeManagers.Tests`:
181 passed, 0 failed, 1 skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`DataTypesClientModel` called `LoadAsync(true, true)` on the complex type
system, and the first parameter of that method is `onlyEnumTypes`. The client
therefore built no structured type at all, and every structure the server
serves arrived as an undecoded extension object - in a sample whose entire
point is that "a value of a structure the client has no compiled knowledge of
arrives decoded into its fields".

Nothing caught it, because the tier 1.7 fixture asserted against
`WrappedValue.ToString()` and the generated default value used to arrive as the
bare XML of the model design (UA-.NETStandard#4401): the raw text happened to
contain "Trek", "Cube" and "10", so the assertions held on an undecoded value.
The bump to 2.0.301.4181-preview fixed that generator defect, the body became a
binary `ByteString`, and the fixture started reporting `Byte[35]`.

Both arguments are named at the call site now, and the `KnownIssue` wrapper
recording the null TypeId is removed with the assertion left standing: the
value carries a real encoding id and decodes into its fields.

The two expectations tier 1.7 still records - a compiled type cannot hand over
its own `DataTypeDefinition` (UA-.NETStandard#4424) and the AlarmCondition
audit trail records no `AddComment` - stay ignored. The audit note is narrowed:
the RoleSet Methods of the RoleManagement sample are audited on this stack, so
"no audit event of any type reaches a subscriber" is no longer true.

`SampleClientModels.Tests`: 421 passed, 0 failed, 3 skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@romanett
romanett merged commit e637435 into master Sep 8, 2026
9 checks passed
@romanett
romanett deleted the romanett/gh-preview-upgrade-d536f2 branch September 8, 2026 19:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant