Bump OPC UA packages to 2.0.0-preview.2 and migrate the breaking API changes - #785
Merged
Merged
Conversation
romanett
force-pushed
the
romanett/bump-nuget-2.0.0-preview.2
branch
from
August 26, 2026 05:11
43924ee to
fe0a52b
Compare
romanett
changed the base branch from
romanett/migrate-sample-configs-to-datatype
to
master
August 26, 2026 05:11
…changes The opcua-preview feed no longer publishes 2.0.158.59919-preview; 2.0.0-preview.2 is now the only version available, so restore fails on any clean machine and CI cannot build. Bump all 43 project files across the 14 OPCFoundation packages. The bump alone is not enough: 2.0.0-preview.2 carries breaking API changes that produce ~21 compile errors in sample code. Migrate each to its documented replacement. - SecurityPolicies is no longer static; it is a sealed class implementing ISecurityPolicyRegistry. The 17 GetDisplayName/GetUri/GetDisplayNames call sites now go through SecurityPolicies.Default, which the API documents as the registry for code with no container in scope - exactly these WinForms dialogs. - The new Opc.Ua.Decimal built-in shadows System.Decimal in files that import Opc.Ua. The affected NumericUpDown bounds now use the decimal keyword. - INodeManager.TransferMonitoredItems gained a MonitoredItemTransferOptions parameter. CustomNodeManager, SampleNodeManager and QuickstartNodeManager get the six-argument overload holding the logic, with the old five-argument form delegating to it - the same shape the SDK's own CustomNodeManager2 uses. The implementation honours DeferInitialValues by skipping SetupResendDataTrigger, which the owning subscription then drives after it commits the transfer. - Session, Subscription and IServerInternal no longer expose DiagnosticsLock, and ISession.SessionDiagnostics is gone. Reads go through ReadDiagnostics, which applies the projection while holding the lock the object owns. The two Server.DiagnosticsLock blocks did not touch the diagnostics summary that lock guarded - they used it as an incidental general lock - so they simply drop it. - ISession.Save/RestoreHistoryContinuationPoint moved to Session.ContinuationPoints.SaveHistory/RestoreHistory, which take and return IHistoryContinuationPoint. HistoryDataReader and the two HistoryReadRequest holders implement that interface and carry their own Id, replacing the separately generated Guid. - NodeBrowser.DataLock is gone: browsers are single-consumer and the base type documents that derived browsers are not expected to synchronize. The six Next() overrides drop the lock. - NodeState.FindChild gained a defaulted assignInstanceNodeIds parameter. Callers are unaffected but overrides must match, so the 23 overrides in the generated model files take it and forward it to base. Verified: all five solutions in the repository build clean in Release, including both solutions CodeQL builds. The configuration work on the parent branch still holds on the new packages - all nine ParseExtension call sites bind, HistoricalAccess still reads ArchiveRoot ".\Archive", and the AlarmCondition encoder still emits WriteEncodeableArray with no ExtensionObject wrapping. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
romanett
added a commit
that referenced
this pull request
Aug 26, 2026
Merging master brought in the package bump from #785, but the nine SourceGeneration analyzer references this branch adds exist only here, so the merge left them pinned to 2.0.158.59919-preview - a version the opcua-preview feed no longer publishes. Git could not flag it as a conflict because nothing on master touches those lines. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
romanett
added a commit
that referenced
this pull request
Aug 26, 2026
…onfigs (#783) * Seal [DataType] config classes and migrate remaining [DataContract] configs AreaConfiguration was a non-sealed partial class, so the source generator's default StructureHandling.Auto resolved to ExtensionObject wrapping for both AlarmConditionServerConfiguration.Areas and AreaConfiguration.SubAreas. The shipped AlarmConditionServer.Config.xml stores plain nested <AreaConfiguration> elements with no ExtensionObject/TypeId wrappers, so the area tree silently decoded as empty (0 of 8 areas, no exception). Auto resolves to inline encoding only when the field's type is sealed and has no IEncodeable base; otherwise it wraps in an ExtensionObject to allow subtyping. Sealing the config types is the fix, and none of them is subclassed anywhere in the repo. - Seal the 10 existing [DataType] types. AreaConfiguration, MemoryBufferInstance and PerformanceTestResultItem are used as property types, so only those change generated encoding; the rest are sealed for consistency so the same bug cannot reappear when a nested property is added. - Migrate the 9 remaining [DataContract] server configs to [DataType] sealed partial classes and drop the DataContractSerializer-only [OnDeserializing] hooks and now-unused usings. All 9 are empty (no [DataMember] properties) and none is ever deserialized - each node manager hardcodes m_configuration = null and falls back to a new instance - so this is a format change only. - Add the OPCFoundation.NetStandard.Opc.Ua.SourceGeneration analyzer reference to the 9 projects that need it. Analyzers do not flow through ProjectReference, and HistoricalAccess Server already carried [DataType] annotations that no generator ever acted on. UA Sample Controls deliberately keeps no analyzer reference: PerformanceTestResult is still round-tripped through DataContractSerializer in PerformanceTestDlg, and its TestCaseResults is a private List<T> rather than ArrayOf<T>. Only the sealing is applied there and its live serializer hooks are left intact. Verified: AlarmCondition config now decodes all 8 areas across three levels of nesting (0 before), the generated encoder switched from WriteEncodeableArrayAsExtensionObjects to WriteEncodeableArray, and ParseExtension<BoilerServerConfiguration> now returns an IEncodeable instance. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Re-enable ParseExtension for the migrated sample server configurations Now that these config types are source-generated IEncodeable implementations, ParseExtension<T> can bind them again. It constrains T to IEncodeable, new(), which is why these call sites were stubbed out to m_configuration = null during the 2.0 migration. Replace the stub with the real call in nine node managers: Boiler, DataAccess, DataTypes, Empty, HistoricalEvents, Methods, PerfTest, SimpleEvents and HistoricalAccess. The existing "use suitable defaults if no configuration exists" fallback is left in place. Two of them did not actually bind and needed their namespaces reconciled first; both failed silently, falling back to defaults rather than raising an error: - HistoricalAccess used a bare [DataType], so its namespace defaulted to urn:quickstarts.historicalaccessserver while the shipped config declares http://opcfoundation.org/Quickstarts/HistoricalAccess. This is the only one of the nine that carries real data, so ArchiveRoot silently stayed null instead of reading ".\Archive". Bound explicitly to Namespaces.HistoricalAccess. - DataTypesServer.Config.xml declared xmlns="http://somecompany.com/DataTypes", which matches no constant in the project. Corrected to urn:localhost:somecompany.com:DataTypesServer, the value of Quickstarts.DataTypes.Namespaces.DataTypes and the server's own primary node namespace, making it consistent with the other eight samples. AggregationServerConfiguration is deliberately untouched: it has no node manager field, no consumer, and no element in Quickstarts.AggregationServer.Config.xml, so there is no ParseExtension call to restore. Verified by loading each shipped Config.xml and calling ParseExtension<T>: all nine now bind and return an IEncodeable instance, and HistoricalAccess reads ArchiveRoot = ".\Archive". Reverting either namespace fix reproduces the silent null on that sample. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Pin the added analyzer references to 2.0.0-preview.2 Merging master brought in the package bump from #785, but the nine SourceGeneration analyzer references this branch adds exist only here, so the merge left them pinned to 2.0.158.59919-preview - a version the opcua-preview feed no longer publishes. Git could not flag it as a conflict because nothing on master touches those lines. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why CI is failing
The
opcua-previewfeed no longer publishes2.0.158.59919-preview.2.0.0-preview.2is now the only version available, sonuget restorefails on any clean machine — including CI. Local builds keep working only because the old package is still in a developer's NuGet cache.The bump alone does not fix it
2.0.0-preview.2carries breaking API changes. With the old version both CodeQL solutions build with 0 errors; with only the version strings changed they produce ~21 and ~28 distinct errors. So this PR does both: the bump, and the API migration it forces.Bump: all 43
.csprojfiles, covering all 14OPCFoundation.NetStandard.Opc.Ua.*packages. Every one verified present at2.0.0-preview.2on the feed before changing anything.API migrations
SecurityPoliciesno longer static — nowsealed class SecurityPolicies : ISecurityPolicyRegistrySecurityPolicies.Default, documented as the registry for "code with no container in scope" — exactly these WinForms dialogsOpc.Ua.Decimalbuilt-in shadowsSystem.Decimaldecimalkeyword for theNumericUpDownboundsINodeManager.TransferMonitoredItemsgainedMonitoredItemTransferOptionsCustomNodeManager2DiagnosticsLockremoved from Session/Subscription/IServerInternal;ISession.SessionDiagnosticsgoneReadDiagnostics(d => …), which applies the projection while holding the lock the object ownsISession.Save/RestoreHistoryContinuationPointremovedSession.ContinuationPoints.SaveHistory/RestoreHistory, takingIHistoryContinuationPointNodeBrowser.DataLockremovedNodeState.FindChildgained defaultedassignInstanceNodeIdsbase(callers are unaffected; only overrides must match)Judgment calls worth a look
TransferMonitoredItemshonoursDeferInitialValuesrather than ignoring it: when set,SetupResendDataTriggeris skipped so the owning subscription drives it after committing the transfer. Passing the flag through would have been enough to compile; this makes the samples actually correct against the new contract.Server.DiagnosticsLockblocks simply drop the lock. Neither touches the server diagnostics summary that lock guarded — one mutatesHistoryServerCapabilitiesnodes duringCreateAddressSpace, the other guards namespace-table mapping.UpdateServerDiagnosticsis the documented replacement but is the wrong tool for both, and the lock is now private.HistoryDataReader/HistoryReadRequestnow implementIHistoryContinuationPointand carry their ownId, replacing the separately generatedGuidthe old two-argumentSaveHistoryContinuationPointtook.FindChildchanges are in generated model files. They are edited in place rather than regenerated, matching what the current generator emits. Regenerating those models is a larger, separate job.Verification
UA Quickstart Applications.sln,UA Sample Applications.sln) plusUA Aggregation.sln,UA Global Discovery Server.slnandUA Samples.slnx.2.0.0-preview.2.2.0.158.59919-previewreference remains in any project or props file.Relationship to #783
#783 (sealing and config migration) adds
SourceGenerationanalyzerPackageReferences to nine projects. Those are not in this PR — they arrive with #783, and will need the same2.0.0-preview.2version whenmasteris merged into that branch after this one lands.🤖 Generated with Claude Code