24 Commits
Author SHA1 Message Date
Marc Schier 0000513cde Pluggable user-identity provider model (#3807)
# Description

Introduces a pluggable user-identity provider model covering all OPC UA
Part 6 §6.5 mechanisms (Anonymous, UserName, X509, IssuedToken/JWT) on
both client and server, with full
`Microsoft.Extensions.DependencyInjection` integration, plus the Part 12
§9 `AuthorizationService` two-phase token-request flow **including
refresh-token rotation**, the Part 12 §8 KeyCredential Push model, and a
clean provider model for OPC 10000-12 §7.2 `ApplicationSelfAdmin`. The
work is split across phase-by-phase commits so it can be reviewed
independently; nothing here changes wire-level behaviour or forces
existing applications to migrate.

### Documentation

All under `Docs/`:

- `IdentityProviders.md` — full developer guide: three-layer model,
recipes, configuration reference, "what gets auto-wired" matrix, JWS
algorithm table, identity-augmenters section, **"Implementing your own
provider"** how-to subsections for Entra / OIDC / Windows / AspNetCore
(sibling files merged in per review feedback).
- `DependencyInjection.md` — `Identity` sections with `appsettings.json`
examples, identity-extension matrix, `WithAuthorizationService` +
`WithKeyCredentialPush` + `AddIdentityAugmenter` extensions documented.
- `RoleBasedUserManagement.md` — claim-criteria callout describing
`IIdentityClaims` probe surface.
- `AuthorizationService.md` — Architecture diagram +
`IAccessTokenProvider` conceptual narrative restored from master; modern
`StartRequestToken` / `FinishRequestToken` flow leads; refresh-token
recipe added.
- `KeyCredentialService.md` — Push model + Pull vs Push vs Bridge
decision matrix + Hybrid (Push + Pull) section; explicit experimental
warning for the bridge.
- `GDS.md` — KeyCredential Push, `StartRequestToken`,
`GdsApplicationSelfAdminProvider`, **shipped Refresh-token support with
rotation policy and audit semantics** all documented.
- `MigrationGuide.md` — User Identity Providers section listing
`[Obsolete]` markers + mechanical recipes; SelfAdmin migration via
`IIdentityAugmenter`; `EnableRefreshTokens` default note.
- `README.md` index entries.

## Checklist

- [x] 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.
- [x] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed.
- [x] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [x] I have addressed **all** PR feedback received.
2026-06-02 01:14:54 +02:00
Marc Schier 889572472f Convert DataValue from class to readonly struct for further GC relief (#3796)
Convert `DataValue` from a mutable reference type (`class`) to a `readonly struct` to eliminate per-allocation GC pressure on every attribute read, subscription publish, and history sample.

### Key API changes (user-visible)

| Before | After | Pattern |
|---|---|---|
| `class DataValue` | `readonly struct DataValue : INullable` | Foundation |
| `Equals(DataValue?)` / `operator ==(DataValue?, DataValue?)` | `Equals(DataValue)` / `operator ==(DataValue, DataValue)` | Value semantics |
| `IEncoder.WriteDataValue(string?, DataValue?)` | `IEncoder.WriteDataValue(string?, DataValue)` | Non-nullable wire API |
| `IDecoder.ReadDataValue(...) -> DataValue?` | `IDecoder.ReadDataValue(...) -> DataValue` | Same |
| `IDataChangeMonitoredItemQueue.PeekLast/Oldest()` | `TryPeekLastValue/Oldest(out DataValue)` | TryGet pattern |
| `IAggregateCalculator.GetProcessedValue(bool)` | `TryGetProcessedValue(bool, out DataValue)` | Same |
| `IUaPubSubDataStore.ReadPublishedDataItem(...)` | `TryReadPublishedDataItem(NodeId, uint, out DataValue)` | Same |
| `Dictionary<uint, DataValue?>` (NodeCacheContext) | `Dictionary<uint, DataValue>` | Default + IsNull |
| `IHistoryDataSource.FirstRaw/NextRaw` | `TryFirstRaw/TryNextRaw(out DataValue)` | TryGet pattern |
| `NodeState.ReadAttribute(... DataValue)` | `NodeState.ReadAttribute(... ref DataValue)` | Sync mutation via ref |
| `NodeState.ReadAttributeAsync(... DataValue)` | `NodeState.ReadAttributeAsync(...) -> ValueTask<(ServiceResult, DataValue)>` | Async return tuple |
| `obj as DataValue` (heterogeneous Dictionary<string, object>) | `obj is DataValue dv ? dv : default(DataValue)` | Safe struct cast |
| `Assert.That(dv, Is.Not.Null)` (tests) | `Assert.That(dv.IsNull, Is.False)` | Struct test pattern |
| `[Obsolete] Value` setter, all property setters | Removed; use ctor or `With*()` | Immutability |
| `[DataContract]` + `[DataMember]` | Removed; surrogate via `SerializableDataValue` + `DataValueSurrogateProvider` | Serialization |

### Wire format

Wire format is **byte-identical** to the previous class-based implementation across binary / JSON / XML encoders. Default DataValue (`.IsNull == true`) is treated as the equivalent of the old null reference (writes JSON `null`, binary `byte 0`, XML omitted element).

### Why TryGet pattern (instead of leaving `DataValue?`)

For methods that previously returned `DataValue?` to signal "no value available" (queue peek, aggregate result, data store lookup, history navigation), the conversion to `bool TryGet(out DataValue)` matches BCL conventions (`Dictionary.TryGetValue`, `Queue.TryPeek`, `Int32.TryParse`) and gives the caller an explicit "may be absent" affordance without `Nullable<DataValue>` overhead.

### Breaking changes summary

- `DataValue` is now a `readonly struct` - boxing/unboxing semantics change for callers using `object`-typed APIs.
- `IEncoder.WriteDataValue` / `IDecoder.ReadDataValue` / `ReadDataValueArray` interface signatures lose the `Nullable` wrapper.
- `IDataChangeMonitoredItemQueue.PeekLastValue` / `PeekOldestValue` -> `TryPeekLastValue` / `TryPeekOldestValue` (out parameter).
- `IAggregateCalculator.GetProcessedValue` -> `TryGetProcessedValue` (out parameter).
- `IUaPubSubDataStore.ReadPublishedDataItem` -> `TryReadPublishedDataItem` (out parameter).
- `NodeState.ReadAttribute` takes `ref DataValue`; `ReadAttributeAsync` returns `ValueTask<(ServiceResult, DataValue)>`.
- `DataValue` property setters removed (use constructor + `With*` mutators).
2026-05-23 11:38:49 +02:00
Marc Schier 70b4498db8 Certificate manager and ref counted certificate type (#3688)
* New certificate and secrete abstraction with certificate infrastructure and certificate/secret stores. 
* leak testing for certificate resources to validate new ref counting in every test assembly
* Migration guide updated and documentation added for all
* Remove IDisposable from Nodestate and UserIdentity.
* UserCertificateTokenHandler now just points into certificate registry/stores, no dispose required
* Fix CA2000 warnings and cleanup of other diagnostics, increase warning levels in .editorconfig
2026-05-12 07:56:38 +02:00
Copilot 54cc3d88b1 Prepare for C# 15 union types: UnionAttribute polyfill, TryGetValue rename, HasValue (#3727) 2026-05-02 18:33:46 +02:00
Marc SchierandCopilot b2cbf6b03b Fix DataValue(int) overload resolution bug (#3721)
new DataValue(42) silently resolved to DataValue(StatusCode) instead of
DataValue(Variant) due to C# 'better conversion target' rule — StatusCode
wins because it implicitly converts to Variant, making it 'more specific'.
This caused m_value = Variant.Null and downstream BadTypeMismatch failures.

Changes:
- Add [OverloadResolutionPriority(1)] on DataValue(Variant) constructor
- Obsolete DataValue(StatusCode) and DataValue(StatusCode, DateTimeUtc)
- Add DataValue.FromStatusCode() static factory methods (2 overloads)
- Delete DataValue(DataValue) copy constructor
- Add DataValue.Copy() instance method using base.MemberwiseClone()
- Rewrite Clone()/MemberwiseClone() to delegate to Copy()
- Migrate all call sites across 14 files
- Add tests verifying new DataValue(42) wraps value correctly
- Update MigrationGuide.md

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 14:24:45 +02:00
Marc Schier 38227cbeab Fix boolean default should be false instead of true (#3679)
* Fix boolean default should be false instead of true
* Update MigrationGuide for boolean default value changes

Clarified the impact of the boolean default value change and updated the migration guide to reflect the correct initialization requirements.
2026-04-20 16:40:43 +02:00
Marc Schier 6c8c1a6d29 Enable dispose analyzers CA2000 and CA2213 and fix all issues (#3670) 2026-04-17 13:39:34 +02:00
Marc Schier 64ca85fce3 Increase code coverage across solution (#3662)
Add additional tests to increase code coverage across the solution
2026-04-14 13:32:10 +02:00
Marc Schier fd41681f4b Add support to publish OPC UA applications as Native AOT (#3633)
* make most ptojects aot compatible
* Remove newtonsoft
* Migrate all projects from Mono.Options to System.CommandLine 2.0.5
* Fix array clone
* Replace serializers for storage using new attribute driven  type geberator
* Add new AOT integration tests covering all functional areas
* Documentation updates
2026-04-13 20:52:29 +02:00
Marc Schier 5a1e547250 Code cleanup and modernization of test assertions to comply with project standards. (#3631) 2026-03-19 21:09:40 +01:00
Marc Schier 03777ecb09 New Json decoder/encoders, array/matrix abstractions, ByteString, and more. (#3619)
- **Collections overhaul** — new/rewritten collection types (`ArrayOf`, `Collections` commits)
- **`Variant` builder/accessor** — new APIs for constructing and accessing Variants
- **`NodeId` operators made explicit** — breaking change for implicit conversions
- **Version bumped to 1.6** with preview build support
- **NumericRange** uses Variant
- **object** type accessors and general usage removed.

### 🏗️ Infrastructure
- Build config updated; `.NET 10` targeting
- InternalsVisibleTo moved to `.csproj`
- Pipeline/CI adjustments
2026-03-18 12:23:30 +01:00
Marc Schier f66ceffd75 Immutable built in types and code generation (#3534)
Generate stack and application code using source generators
Change built in types to readonly structs
  Update localized text implementation to use JSON text serializer
  Status code with symbolic names
  Immutable node ids
  No boxing for all built in types <= 8 bytes in Variant.
Split user identity token and token handling via token handler
Add migration guide for breaking changes
2026-02-12 16:27:07 +01:00
Marc Schier 2960388560 Update headers and license files (#3388)
Update license headers to copy right year 2025, replace RCL/GPL headers with MIT, replace the nuget license with MIT (via license expression).
2025-12-04 19:44:40 +01:00
Copilotandromanett 8493e73a18 Fix KeyFrame not sent if no changed values (#3367)
* Initial plan

* Fix KeyFrame not sent if no changed values (Issue #2622)

The MessageCount was only incremented in OnMessagePublished() which is only called when a message is actually published. When there are no data changes, no message is published, so MessageCount stayed the same and KeyFrames were never sent after the initial one.

The fix moves the MessageCount increment to IsDeltaFrame() so it tracks publishing intervals instead of actual messages published. This ensures that after KeyFrameCount intervals, a key frame is sent regardless of whether data changed.

Co-authored-by: romanett <7413710+romanett@users.noreply.github.com>

* Address code review: Use direct cast instead of Convert.ToUInt32

Co-authored-by: romanett <7413710+romanett@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>
2025-12-03 09:41:10 +01:00
Marc Schier 8e7a73c7df Introduce telemetry context and proper use of ILogger (#3213) 2025-09-25 20:25:31 +02:00
Marc Schier 9830e5d53e Enable roslynizer and fix all analyzer issues (#3157)
* Fix warnings and suggestions
* Enable roslynator
2025-08-16 04:10:24 -07:00
fe0aec4969 1.05.04 final release fixes (#2893)
* Add missing constants for JSON encoding.

* Update generated files to 1.05.04.

* Update NuGets

* Fix compile errors due to abstract types.

* Update nodesets.

* Update JSON Encoder/Decoder.

* Update with JSON encoder.

* Change prefix char.

* Change prefix to uppercase.

* Fix JsonEncoder

* Fix null pointer.

* Update encoders to suppress artifacts.

* JSON encoding fixes.

* Fix JSON RawEncoding

* Update JSON encoders.

* Revert changes for Matrix in Variant.

* Update NodeSet.

* Resolve name conflict with new Opc.Ua types.

* Fix failing Tests

* Fix unit tests after change to Verbose/Compact encoding.

* Add final 1.05.04 generated classes and unit test fixes.

* Fix more unit tests.

* Update NodeSet to released version.

* Remove unintended changes to UANodeSet.xsd

* Update Schema/UANodeSet.xsd

* Merge breaking changes to JsonEncoder.cs from develop/main374

* Allow JObject in ExtensionObjects.

* fix version json

* Update generated files to UA-1.05.04-2025-01-08

* Some cleanup of the new APIs and Union implementation. (#2927)

* Some cleanup of the new APIs and Union implementation.

* fix build

* Handle status code Uncertain according to the specification (#2898)

* #2896: Write output arguments for good and uncertain status code

When a method state's call method is invoked the output arguments should be written in case the status code is good or uncertain. This behavior would be conform with the current specification.

* #2896: The service result corresponds the method call result

The result of the Call method in the CustomNodeManager2 class represents the status of the CallMethodResult. It does not correspond to the ServiceResult of the CallResponse, thus returning Good as a general response is incorrect behavior.

* Add SetHiResClockDisabled  & fix Rejected Store Creation in ApplicationConfigurationBuilder (#2909)

Add the method SetHiResClockDisabled to IApplicationConfigurationBuilder
Fix the type of RejectedStore Created by the Builder to: CertificateStoreIdentifier

* revert based on feedback

* move some logic from class code to encoder/decoder

* Fix race condition on Nuget build (#2930)

- nodeset xmlzip is created in obj folders if multiple targets are built in parallel

* update common comments

* Update NodeSet files.

* Fix ReadSwitchField Implementation.

* Make UserIdentity.DisplayName writeable.

* Fix merge failures.

* Fix XmlElement encoding and bad NamespaceIndex fallback logic.

* Fix 2D array raw encoding.

* Add support for DesignToolOnly.

---------

Co-authored-by: Randy Armstrong <randy@sparhawksoftware.com>
Co-authored-by: Martin Regen <mregen@microsoft.com>
Co-authored-by: Martin Regen <7962757+mregen@users.noreply.github.com>
2025-03-07 15:25:33 +02:00
dependabot[bot]andRoman Ettlinger 60689c9431 Bump NUnit from 3.14.0 to 4.1.0 (#2535)
* Bump NUnit from 3.14.0 to 4.1.0

Bumps [NUnit](https://github.com/nunit/nunit) from 3.14.0 to 4.1.0.
- [Release notes](https://github.com/nunit/nunit/releases)
- [Changelog](https://github.com/nunit/nunit/blob/master/CHANGES.md)
- [Commits](https://github.com/nunit/nunit/compare/v3.14.0...4.1.0)

---
updated-dependencies:
- dependency-name: NUnit
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix Build by adding: using Assert = NUnit.Framework.Legacy.ClassicAssert;

Co-authored-by: Roman Ettlinger <romanett98@gmail.com>
2024-04-22 13:29:30 +02:00
Suciu Mircea Adrian 553a869d4f Added KeyFrameCount and DeltaFrame tests (#2579)
Added tests which include PubSub KeyFrameCount and DeltaFrames.
2024-04-11 08:23:32 +02:00
Martin Regen 4c0880c800 Fix codesmells. No functional changes and bug fixes. (#2368)
Fix many warnings to improve code quality or simplify the code.
2023-11-07 10:34:42 +01:00
Martin Regen cfc68eeb10 Use .NET analyzers instead of Roslynator, fix warnings, no bug fixes (#1729)
-use latests analyzers in .NET instead of Roslynator.
-fix warnings and formatting, no bug fixes!
2022-03-14 16:39:09 +01:00
Suciu Mircea Adrian 75744e27dd Support Metadata frames in PubSub (#1518)
Refactored WriterGroupPublishState out of IPubSubConnection file
    JSON Discovery messages for DataSetMetaData
    UADP Discovery messages for DataSetMetaData (Request + response)
    Refactored the UaPublisher, extracted IntervalRunner and reused it in UdpDiscoveryPublisher & UdpDiscoverySubscriber
    Proposal: automatic setting of ConfigurationVersion based on the rules in 6.2.2.1.5 (part 14)in new class Opc.Ua.PubSub.Configuration.ConfigurationVersionUtils
    New events added to UaPubSubApplication
    Implemented support for UADP Data Key Frame DataSetMessages

    Unit tests were updated to cover the new functionality
2021-09-28 11:54:37 +03:00
Alin Moldovean 08164fe04a MetaData support for PubSub library (#1452)
* Metadata support
* Fixes for UaPubSub.
* Add support for delta frames.
2021-07-08 19:29:24 +03:00
Alin Moldovean 7a4a22201b MQTT support in PubSub library (#1376)
Implementation of MQTT support in PubSub library
2021-04-28 15:31:06 +03:00