Commit Graph
6 Commits
Author SHA1 Message Date
6e0ed89d3f Make UANodeSetSerializers.g.cs generation deterministic (#4252)
## Problem

Regenerating `src/Opc.Ua.Types/Schema/UANodeSetSerializers.g.cs` via
`UANodeSetSerializers.ps1` produced ~144 lines of no-op churn on every
run. The sgen tool (Microsoft.XmlSerializer.Generator) emits the Reader
`idNN_Name` field declarations and the matching `InitIDs()` initializers
in a hash-seed-dependent order: the assigned id numbers are stable, but
their emission order shuffles between runs. This made an otherwise no-op
regeneration produce a large, noisy diff that was painful to review.

## Fix

- Added a canonicalization pass in `UANodeSetSerializers.ps1` that sorts
each of the two affected contiguous blocks (the `string idNN_Name;`
field declarations and the `idNN_Name = Reader.NameTable.Add(...)`
initializers) by numeric id ascending, so re-running on unchanged input
yields byte-identical output.
- The name regex was widened to `@"[^"]*"` so entries with an empty name
(e.g. `id3_Item`) or URI-style names do not split the block into
independently-sorted runs (which would keep it unstable).
- Regenerated the committed `.g.cs` once through the improved script;
the resulting diff is sort-only.

## Also fixed: tool download

Replaced `Expand-Archive` (which rejects the `.nupkg` extension on
Windows PowerShell) with
`System.IO.Compression.ZipFile.ExtractToDirectory`, so a clean run with
an empty tool cache works end-to-end on both Windows PowerShell 5.1 and
PowerShell 7+.

## Validation

- From an empty tool cache, the full download + extract + generate path
succeeds.
- A second run is a byte-identical no-op (`git diff --exit-code` = 0).
- `dotnet build src\Opc.Ua.Types\Opc.Ua.Types.csproj -c Release -f
net10.0` builds with 0 warnings and 0 errors.
- All AOT post-processing is preserved: custom header, `#if
NET5_0_OR_GREATER` wrapper, module IL2026/IL3050 suppressions,
`[RequiresUnreferencedCode]`/`[RequiresDynamicCode]` on the
InitCallbacks() overrides (Writer = RequiresUnreferencedCode only,
Reader = both), pragmas, UTF-8 BOM, and CRLF line endings.

No hand-edits to `.g.cs`; the fix lives entirely in the script so future
regenerations stay stable.

## Also: Load UserAccessLevel from NodeSet2 model

Bundled here because it regenerates `UANodeSetSerializers.g.cs`, which
this PR owns.

- `UANodeSet.cs`: adds the `{Member}Specified` XmlSerializer convention
to `UAVariable.UserAccessLevel` (new `UserAccessLevelSpecified`
companion; removed the `[DefaultValue((uint)1)]`) so an
explicitly-present `UserAccessLevel` attribute is distinguishable from
the schema default of 1.
- `UANodeSetSerializers.g.cs`: regenerated - the writer now emits
`UserAccessLevel` when `UserAccessLevelSpecified`, and the reader sets
`UserAccessLevelSpecified = true`. Regenerating produced only these two
behavioral changes plus removal of pre-existing empty `if
(o.@MemberSpecified) { }` no-op blocks (see below); no `idNN` re-sort,
so determinism held.
- `UANodeSetHelpers.cs`: the runtime importer honors an
explicitly-specified `UserAccessLevel` instead of always deriving it
from `AccessLevel`.
- Source generator (`ModelDesign.cs` `RawUserAccessLevel`,
`ModelDesignExtensions.GetUserAccessLevelAsCode`,
`NodeSetToModelDesign.cs`): emit the verbatim `UserAccessLevel` when the
NodeSet sets it, otherwise derive from `AccessLevel` (matching the
runtime importer).

### Generator normalization for `{Member}Specified`

sgen emits an extra empty `if (o.@MemberSpecified) { }` no-op block near
`WriteEndElement` for every member that uses the `{Member}Specified`
convention. Adding the companion to `UserAccessLevel` would have
introduced one such block, and the committed file already contained
several for other members (`LastModified`, `AccessRestrictions`,
`PublicationDate`). `UANodeSetSerializers.ps1` now strips these empty
guard blocks during post-processing, so the generated file stays free of
dead code and a re-run of the generator remains a byte-identical no-op.
The real, non-empty guard around the `WriteAttribute` call is preserved.

The ReferenceServer sample application of this feature is intentionally
excluded and lands with #4220.

### Validation (UserAccessLevel)

- `dotnet build src\Opc.Ua.Types\Opc.Ua.Types.csproj -c Release -f
net10.0` and `dotnet build
tools\Opc.Ua.SourceGeneration.Core\Opc.Ua.SourceGeneration.Core.csproj
-c Release`: both 0 warnings / 0 errors.
- `dotnet test tests\Opc.Ua.SourceGeneration.Core.Tests -c Release -f
net8.0 --filter
"FullyQualifiedName~NodeSetToModelDesign|FullyQualifiedName~UserAccessLevel"`:
16 passed, 0 failed.
- Re-running the generator remains a byte-identical no-op.

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: romanett <7413710+romanett@users.noreply.github.com>
2026-08-14 08:00:13 -07:00
Marc SchierandCopilot e73e71184d [WotCon] Add OPC UA WoT Connectivity 1.1 with the Types, source generation, Server and xRegistry work it builds on (#4128)
## Summary

Adds OPC UA WoT Connectivity 1.1 to the stack, together with the Types,
source generation, Server and xRegistry work it is built on. This branch
is the merge point for the fourteen-PR stack that replaced integration
PR #4093; every constituent PR was reviewed and approved separately and
is listed below.

414 files changed, +108,936 / -3,199. Roughly 46k added lines of product
code, 57k of tests, plus samples, tools and documentation.

## Types

- Complete `ExtensionObject` raw-body decoding for binary, XML and JSON
bodies by resolving the concrete type through the message context's
encodeable factory, and simplify the `Variant` structure helpers by
delegating to it (#4128).
- Add `IAtomicFileReplace` as an optional `IFileSystem` capability so
existing external implementations keep working, with atomic publish for
`LocalFileSystem` via `File.Replace`/`File.Move` and for
`VirtualFileSystem` by re-keying the in-memory entry (#4128).
- Add lossless conversion between WoT documents and NodeSet2
(`Opc.Ua.Wot.WotNodeSetConverter`). A byte-exact `uav:nodeSet` envelope
is preserved when requested, the structured `uav:nodes` projection is
used when the readable vocabulary is incomplete, and NodeSet2 is
otherwise synthesized from readable WoT terms. Unmapped JSON members
survive a round trip as pointer-addressed residue (#4131).

## Source generation

- Improve the NodeSet to ModelDesign conversion and the generated node
state (#4132).
- Generate OPC UA models directly from WoT Thing Description files
(#4134).

## Server

- Add live NodeManager shadow and immediate reload. A reload
materializes a new generation beside the active one and switches
atomically; the superseded generation is retired gracefully so existing
MonitoredItems keep being served until they drain, or immediately when
the caller asks for it. Includes the request admission and drain
machinery that lets an orderly shutdown wait for admitted requests
instead of tearing down underneath them (#4147).
- Make subscription transfer between sessions transactional, so a failed
transfer leaves neither session holding a partially moved subscription
(#4150).

## xRegistry

- Allow clients to use explicit registry roots rather than assuming a
well-known location (#4130).

## WoT Connectivity

- Add the WoT Connectivity 1.1 information model: a registry-first
revision layered on the abstract xRegistry base model, incorporating the
complete published OPC 10100-1 v1.02 surface as deprecated nodes in the
same namespace so existing 1.02 clients keep working (#4139).
- Add the protocol binding abstractions and planners that compile WoT
forms into executable plans (#4140).
- Add the HTTP, Modbus, OPC UA and MQTT binding executors (#4144).
- Add the registry and its stores, including document versioning,
validation, dependency resolution and refresh (#4146).
- Add the registry client (#4142).
- Materialize WoT Thing Descriptions into the server address space,
deriving types from Thing Models and instances from Thing Descriptions
(#4154).
- Restore the WoT asset registry bridge so the deprecated 1.02 asset
surface is backed by the registry (#4171).
- Add the WoT Connectivity samples and complete the documentation
(#4156), and restore the remaining coverage and docs (#4172).

## New projects

`src/Opc.Ua.WotCon.Bindings`, `src/Opc.Ua.WotCon.Bindings.Mqtt`,
`tests/Opc.Ua.WotCon.Bindings.Tests`,
`tests/Opc.Ua.WotCon.Samples.Tests`, and the `samples/WotCon`
AggregationServer, AggregationClient and FlatTagServer samples.

## Constituent pull requests

Merged into this branch top-down, each independently approved:

| PR | Title |
| --- | --- |
| #4128 | [Types] Complete ExtensionObject decoding and add an atomic
file replace capability |
| #4131 | [Types] Add lossless conversion between WoT documents and
NodeSet2 |
| #4132 | [SourceGeneration] Improve NodeSet to ModelDesign conversion
and generated node state |
| #4134 | [SourceGeneration] Generate OPC UA models from WoT Thing
Description files |
| #4147 | [Server] Add live NodeManager shadow and immediate reload |
| #4150 | [Server] Make subscription transfer between sessions
transactional |
| #4130 | [XRegistry] Allow clients to use explicit registry roots |
| #4139 | [WotCon] Add the WoT Connectivity 1.1 information model |
| #4140 | [WotCon] Add the WoT protocol binding abstractions and
planners |
| #4144 | [WotCon] Add the HTTP, Modbus, OPC UA and MQTT binding
executors |
| #4146 | [WotCon] Add the WoT Connectivity registry and its stores |
| #4142 | [WotCon] Add the WoT Connectivity registry client |
| #4154 | [WotCon] Materialize WoT Thing Descriptions into the server
address space |
| #4156 | [WotCon] Add the WoT Connectivity samples and complete the
documentation |
| #4171 | Restore WoT asset registry bridge |
| #4172 | Restore WoT coverage and docs |

Supersedes #4093.

## Follow-up

The WoT Connectivity and WoT Binding drafts have moved to 1.1-draft2
since this work was authored. Aligning with that revision - the removed
group vocabulary, the new projection/View construct, the remaining model
vocabulary terms and the two new portable-identity validation rules - is
tracked separately and will follow in its own pull request.

## Validation

Built for every target framework with zero warnings and zero errors, and
validated at the tip of the stack with `Opc.Ua.WotCon.Tests` at 999
passed / 0 failed and `Opc.Ua.Server.Tests` at 4024 passed / 0 failed.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9e6a5abf-3299-4cd1-9855-010fedbf0ad8
2026-08-05 10:14:15 +02:00
Copilot a03bca97cb Remove TraceConfiguration and related APIs (#4092)
# Description

This change removes the remaining `TraceConfiguration`-driven
apply/setter API path and aligns configuration startup with the 2.0
telemetry model (`ITelemetryContext`/`ILoggerFactory`). It also updates
migration docs to make the removal explicit and actionable.

- **Core API removals**
  - Deleted `TraceConfiguration.ApplySettings()` implementation file.
  - Removed runtime apply calls from configuration/server startup paths.
  - Removed fluent builder trace setters:
    - `SetOutputFilePath(...)`
    - `SetDeleteOnLoad(...)`
    - `SetTraceMasks(...)`
  - Simplified builder interface inheritance accordingly.

- **Call-site and test fixture updates**
- Removed usage of deleted trace fluent APIs in affected test
infrastructure and fixtures.
- Updated GDS log readers to tolerate missing `TraceConfiguration`
output path safely.

- **Migration guidance**
- Updated migration docs to explicitly state removal of
`TraceConfiguration` apply APIs and direct users to telemetry-based
logging configuration.

```csharp
// Removed API pattern
app.Build(uri, product)
   .AsClient()
   .SetOutputFilePath("trace.log")
   .SetTraceMasks(Utils.TraceMasks.Error);

// New direction
// Configure logging via ITelemetryContext / ILoggerFactory at composition/startup.
```

## Related Issues

- OPCFoundation/UA-.NETStandard#4091

## Checklist

- [ ] 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.

<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #4091

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-26 00:50:59 +02:00
Marc Schier 2a4bc0fe24 Make reverse connect lifecycle fully asynchronous (#4059)
## Summary

- add cancellation-aware asynchronous start, lazy initialization, stop,
reload, and disposal for `ReverseConnectManager`
- make listener replacement transactional with explicit ownership,
rollback/restoration, stale watcher protection, and deterministic
concurrent start/stop/dispose behavior
- add injectable async configuration providers, remove the former
protected configuration hooks, and retain obsolete synchronous lifecycle
compatibility wrappers
- integrate eager Generic Host startup plus non-host lazy startup,
including custom application-configuration providers
- serialize `ReverseConnectHost` lifecycle and extend raw TCP, Kestrel
TCP, WSS, hosting, concurrency, rollback, and NativeAOT coverage
- document the async lifecycle, hosting behavior, cancellation
guarantees, provider model, and migration path

## Validation

- `Opc.Ua.Client` Release build across all supported target frameworks
- reverse-connect client and core tests on net10.0 and net48
- raw TCP, Kestrel TCP, and WSS integration tests on net10.0; raw TCP on
net48
- NativeAOT publish and 115-test executable run

Closes #4013.

Related: #3985, #4009.
2026-07-23 10:40:32 +02:00
Marc Schier 41a648c9db Fail fast on reverse connect listener startup (#4009)
# Description

Fail reverse-connect listener startup immediately instead of logging
bind failures and surfacing a later connection timeout.

- Validate and stage configured and programmatic listener endpoints
before replacing active configuration.
- Open all listeners atomically and report endpoint-specific failures
with `BadTcpEndpointUrlInvalid`, the transport-specific status, or
`BadNoCommunication`.
- Roll back listeners opened by a failed attempt without reacquiring the
manager lock, including forced listener disposal when normal close
fails.
- Preserve meaningful `ServiceResultException` status codes through both
`StartService` overloads.
- Dispose replaced configuration watchers and reject callbacks from
stale watcher generations.
- Keep the intended shared-listener behavior: one long-lived
`ReverseConnectManager` can accept connections from multiple Servers on
the same Client URL.
- Expand `Docs/ReverseConnect.md` with listener lifetime, shared-manager
usage, diagnostics, and specification references.

## Validation

- `ReverseConnectManagerTests`: net10.0 and net48.
- `ReverseConnectHostTests`: net10.0 and net48.
- Ordered reverse-connect listener reuse integration tests: net10.0.

## Related Issues

- Relates to #3985.

## Checklist

- [ ] 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.
- [x] 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.
- [x] 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.
2026-07-17 13:20:24 +02:00
Marc Schier 7cec2d614d Move repository files to the consolidated layout 2026-07-16 06:25:54 +02:00