Files
UA-.NETStandard/samples/Reference/ConsoleReferenceServer
Copilot e78c648295 Images CI: publish samples once natively and stop compiling under QEMU (#4679)
# Description

Images CI took 45–100 min per image. The arm64 half of every
`linux/amd64,linux/arm64` build ran `dotnet restore` and `dotnet
publish` in an arm64 SDK container under QEMU. For `refserver`, publish
took 8 min natively for amd64 and 92 min emulated for arm64. On top of
that, every one of the 10 matrix legs recompiled the whole stack.

The output is framework-dependent portable IL, so the compile is now
done once, natively. The image legs only copy files onto the
per-platform runtime base image.

### Dockerfiles (all 10)
- **SDK stage runs on the build platform.** The `build` stage is pinned
to `--platform=$BUILDPLATFORM`. `-p:UseAppHost=false` keeps an x64 app
host out of the arm64 image.
- **New `prebuilt` stage.** It is chosen with a global `ARG
PUBLISH_SOURCE`, which defaults to `build`. Local `docker build` and the
`docker-compose` files are unchanged.
  ```dockerfile
  FROM scratch AS prebuilt
  ARG PUBLISH_DIR=artifacts/docker/publish
  COPY ${PUBLISH_DIR}/ /app/publish/

  FROM ${PUBLISH_SOURCE} AS publish
  ```
- **Pump: final-stage `RUN`s moved to a native stage.** The `sed` on
`openssl.cnf` and the `mkdir`/`chown`/`chmod` steps now run in a
`$BUILDPLATFORM` `layout` stage. The final stage copies `/layout/` to
`/`, so `/app` and `/diag` keep the `$APP_UID:0` owner and `g=u` mode
they had before. `openssl.cnf` therefore comes from the build-platform
base image. It is a plain config file, so it is expected to match
between architectures.

### `docker-image.yml`
- **Single image list.** The image list lives once, in `env.IMAGES`
(image, project, Dockerfile). `discover` emits it as the matrix.
- **New `publish-samples` job.** It runs `dotnet publish` for each
sample sequentially, so shared libraries compile once. It uses the same
options and NBGV version properties as the Dockerfiles and uploads the
output as the `docker-publish` artifact.
- **`build-and-push-image` legs.** Each leg:
  - downloads the artifact;
- builds with `PUBLISH_SOURCE=prebuilt` and
`PUBLISH_DIR=artifacts/docker/publish/<image>`;
  - no longer uses `setup-qemu-action`;
  - is named `build-and-push-image (<image>)`.
- **`images summary`.** It now also fails when `publish-samples` fails.

### Docs
- `ContainerReferenceServer.md` describes the publish-once / copy-only
flow and the build arguments.
- `DeveloperGuide.md` mentions the `publish-samples` job in the Images
CI section.

Expected: one native publish of about 7 min, then 10 parallel
copy-and-push legs of a few minutes each. Not yet confirmed on CI: the
sandbox could not pull MCR base images, so the prebuilt multi-platform
builds were checked against a Debian-based stand-in base, and the
build-from-source path was not built.

## Related Issues

## 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.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: romanett <7413710+romanett@users.noreply.github.com>
2026-10-06 14:21:44 +02:00
..

OPC Foundation UA .NET Standard Reference Server

Introduction

The console reference server can be configured using several console parameters. Some of these parameters are explained in more detail below.

To see all available parameters call console reference server with the parameter -h.

Historical Access

The reference server starts with an in-memory Part 11 historian. Its historized scalar nodes expose raw, modified, at-time, aggregate, annotation, and update operations together with populated HistoricalDataConfigurationType companions. CTT/Historical_KeyValuePairs demonstrates generic StructuredHistoryData with two KeyValuePair entries at one timestamp. The CTT notifier exposes historical event read/write bits, a HistoricalEventConfigurationType companion, and seeded event history. Writes to the two event-trigger variables report events; live forwarding completes before the historian snapshots them into its bounded asynchronous capture queue.

Run the matching client workflow with:

dotnet ConsoleReferenceClient.dll --historian --autoaccept --nosecurity \
  opc.tcp://localhost:62541/Quickstarts/ReferenceServer

See docs/HistoricalAccess.md for the provider contracts, status semantics, and custom storage examples.

Reverse Connect

The OPC UA reverse connect feature allows an OPC UA server to initiate the connection to a client, rather than the traditional model where clients connect to servers. This is particularly useful in scenarios where the server is behind a firewall or NAT, making it difficult for clients to directly connect to it.

How to use Reverse Connect

To enable reverse connect mode, specify the client endpoint URL using the --rc or --reverseconnect parameter:

dotnet ConsoleReferenceServer.dll --rc=opc.tcp://localhost:65300

or

dotnet ConsoleReferenceServer.dll --reverseconnect=opc.tcp://localhost:65300

Example: Server and Client with Reverse Connect

  1. Start the client with reverse connect listener on port 65300:

    dotnet ConsoleReferenceClient.dll --rc=opc.tcp://localhost:65300 opc.tcp://localhost:62541/Quickstarts/ReferenceServer
    
  2. In a separate terminal, start the server with reverse connect to the client:

    dotnet ConsoleReferenceServer.dll --rc=opc.tcp://localhost:65300 -a
    

The server will establish a reverse connection to the client endpoint, and the client will use this connection to communicate with the server.

Additional Options

  • -a or --autoaccept: Auto accept untrusted certificates (for testing only)
  • -c or --console: Log to console
  • -l or --log: Log app output
  • -t or --timeout: Timeout in seconds to exit application

For the complete list of options, use --help.

X509 user identity certificates

The reference server validates X509 user identity tokens against its trusted-user certificate store (TrustedUserCertificates, by default %LocalApplicationData%/OPC Foundation/pki/trustedUser). An untrusted user certificate is rejected with BadIdentityTokenRejected — the --autoaccept option only auto-accepts the application/channel certificate, never user identity certificates.

To let a trusted client (for example the OPC Foundation Compliance Test Tool) authenticate with an X509 user token, its user certificate must be present in that store. To make provisioning easy, the server writes every rejected X509 user certificate to a dedicated review store, pki/rejectedUser (a sibling of pki/trustedUser). After one failing activation you can move the legitimate user certificate from pki/rejectedUser/certs into pki/trustedUser/certs (and any issuing CA into pki/issuerUser/certs) and reconnect. Deliberately-untrusted certificates simply stay out of the trusted store and continue to be rejected.