Files
romanett 1af191ec26 Drop the .Common suffix from the three GDS projects (#4438)
# Description

Every other companion specification in the stack ships as `<Family>`,
`<Family>.Client` and `<Family>.Server` — `Opc.Ua.Di`, `Opc.Ua.ISA95`,
`Opc.Ua.Positioning`, `Opc.Ua.Robotics`, `Opc.Ua.Vision`,
`Opc.Ua.WotCon`, `Opc.Ua.XRegistry`, and `Opc.Ua.Lds.Server` without a
family package. GDS was the one exception, carrying a `.Common` suffix
that named nothing.

| Before | After |
| --- | --- |
| `src/Opc.Ua.Gds.Common` | `src/Opc.Ua.Gds` |
| `src/Opc.Ua.Gds.Client.Common` | `src/Opc.Ua.Gds.Client` |
| `src/Opc.Ua.Gds.Server.Common` | `src/Opc.Ua.Gds.Server` |

## No source changes were needed

`RootNamespace` was already the final name in all three projects — the
namespaces have always been `Opc.Ua.Gds`, `Opc.Ua.Gds.Client` and
`Opc.Ua.Gds.Server`, and only `AssemblyName` and `PackageId` disagreed.
Nothing that compiles against these assemblies changes a `using`
directive; the diff outside the moves is entirely ids, paths and prose.

Directories were moved with `git mv`, and every one of the 73 file moves
is detected as a rename at 100% similarity (bar the handful that also
had a name in their text), so `git log --follow` and blame survive.

## Consumer impact

The package ids change, which is visible to anyone consuming the NuGet
packages:

| 1.5.378 package | 2.0 package |
| --- | --- |
| `OPCFoundation.NetStandard.Opc.Ua.Gds.Common` |
`OPCFoundation.NetStandard.Opc.Ua.Gds` |
| `OPCFoundation.NetStandard.Opc.Ua.Gds.Client.Common` |
`OPCFoundation.NetStandard.Opc.Ua.Gds.Client` |
| `OPCFoundation.NetStandard.Opc.Ua.Gds.Server.Common` |
`OPCFoundation.NetStandard.Opc.Ua.Gds.Server` |

`docs/migrate/2.0.x/packages.md` gains a renamed-packages section — it
is the document that undertakes to cover NuGet renames, and had no GDS
entry — and the migration skill's package table gains the two rows a
1.5.378 consumer needs. That is the only hand-written content in this
PR; everything else is mechanical.

Assembly names follow the package ids, so the section also notes that
binding redirects, trimming descriptors and signing manifests naming the
files directly have to be updated.

## Build infrastructure

Everything naming the projects or their output moves with them:

- `UA.slnx` and `tools/MigrationAnalyzer.slnx` (both re-sorted — the
project lists are alphabetical, and `Gds` now sorts before
`Gds.Client`).
- `.azurepipelines/expected-packages.txt` — 3 ids, also re-sorted for
the same reason.
- `.azurepipelines/signlistDebug.txt` and `signlistRelease.txt` — 18
paths each. Their internal ordering is left alone: that group was
already unsorted, and reordering a signing manifest is diff noise.
- `samples/Reference/ConsoleReferenceServer/Dockerfile`, the two
metapackage nuspecs, the analyzer nuspec's package dependencies, and 8
`.csproj` references across tests, samples and tools.

`preview-pack.slnx` is generated from `UA.slnx` by `generate-slnx.ps1`,
so there is nothing static to edit. Nothing under `.github/workflows`,
and no `.ps1`/`.yml` in `.azurepipelines`, names these projects.

The migration analyzer's shim tree mirrors the source project layout by
its own documented convention, so `Gds.Client.Common/` becomes
`Gds.Client/` and its readme table follows.

## Deliberately not changed

Prose naming past work: `plans/23` still records that its deferral
happened during the "GDS Client.Common modernization", which is the name
that effort had. File *paths* in the same document were updated.

## Validation

`net10.0`:

- `UA.slnx`: 0 errors. 14 warnings, all pre-existing
CA1861/CA1850/CA1307 in `XRegistry`, `Types.Tests` and `WotCon.Tests` —
none in anything this PR touches.
- Assemblies build as `Opc.Ua.Gds.dll`, `Opc.Ua.Gds.Client.dll`,
`Opc.Ua.Gds.Server.dll`, with no `*.Common.dll` produced anywhere.
- `Opc.Ua.Gds.Tests`: 1,116 passed, 0 failed, 54 skipped.
- `Opc.Ua.MigrationAnalyzer.Core.Tests`: 10 passed, 3 skipped.
- A repo-wide grep for the old names returns only the intentional old →
new mappings in the migration docs.

## Checklist

- [x] Existing tests pass
- [x] No new tests — this is a rename with no behaviour change
- [x] Consumer-visible package rename documented in the migration guide

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 20:08:54 +02:00
..

OPC 10000-21 Onboarding Demo

This sample demonstrates the registrar-administration part of OPC 10000-21 end to end over a real OPC UA connection. It uses only the model and runtime APIs shipped by this repository:

  • OnboardingRegistrar loads the generated Opc.Ua.Onboarding model, exposes the standard DeviceRegistrar_Administration object, and binds RegisterTickets / UnregisterTickets to an injected MemoryTicketStore.
  • OnboardingClient connects with a managed session, resolves the well-known registrar NodeId, and uses the DI-provided Opc.Ua.Gds.Client.OnboardingClient.
  • run-onboarding-demo.ps1 builds both applications, waits until the OPC UA server reaches its running state, proves an anonymous caller is denied, runs the authenticated client, and stops the exact registrar process in a finally block.

The demo covers ticket administration. It does not implement the device-facing ProvideIdentities flow or a complete production GDS.

Run the complete demo

From the repository root:

pwsh samples/Gds/run-onboarding-demo.ps1

The script uses opc.tcp://localhost:62560/OnboardingRegistrar by default. Select a different port with:

pwsh samples/Gds/run-onboarding-demo.ps1 -Port 62660

Successful output ends with:

REGISTER Good Good
UNREGISTER Good
UNREGISTER_AGAIN BadNotFound
ONBOARDING_DEMO_OK

Pass -Keep to retain the temporary PKI stores and registrar logs for diagnostics.

Run the applications manually

Start the registrar:

dotnet run --project samples/Gds/OnboardingRegistrar -f net10.0 -- `
  --port 62560 `
  --pkiRoot "$env:TEMP\opcua-onboarding-registrar"

After ONBOARDING_REGISTRAR_READY is printed, run the client:

dotnet run --project samples/Gds/OnboardingClient -f net10.0 -- `
  --endpoint "opc.tcp://localhost:62560/OnboardingRegistrar" `
  --pkiRoot "$env:TEMP\opcua-onboarding-client"

Wire contract

The client API uses the Part 21 types directly:

ArrayOf<StatusCode> results = await onboarding.RegisterTicketsAsync(
[
    new ByteString(firstTicket),
    new ByteString(secondTicket)
]);

EncodedTicket is a subtype of ByteString. The server returns one StatusCode for every supplied ticket.

Security

The demo selects SignAndEncrypt with Basic256Sha256. For a self-contained local run, both applications automatically accept the other application's newly created certificate and store it under an isolated temporary PKI root. The script also generates a one-run random username and password, grants that user the generated RegistrarAdmin role, and restricts the two ticket methods to that role. The endpoint also permits an anonymous bootstrap session because ManagedSession activates its configured identity provider after creating the session; anonymous users have no permission to call the registrar methods.

Automatic certificate acceptance is a sample-only convenience. A production registrar must use managed trust lists, authenticate and authorize registrar administrators, persist tickets in a protected store, and apply the audit/redaction requirements described in the GDS developer guide.

For a manual run, set ONBOARDING_DEMO_USER and ONBOARDING_DEMO_PASSWORD to the same non-empty values in both terminals before starting either application. Do not reuse demo credentials in a production deployment.