Files
romanett f4e93eab93 Fix public IsNodeInView/IsNodeInViewAsync overloads always returning false (#4333)
# Description

The public `IsNodeInView(OperationContext, NodeId, object)` in
`CustomNodeManager2` and `IsNodeInViewAsync(OperationContext, NodeId,
object, CancellationToken)` in `AsyncCustomNodeManager` unwrap the
`NodeHandle` and forward `handle.Node` together with the **unchanged**
`OperationContext`. Since there is no `NodeState`-taking overload with
an `OperationContext`, overload resolution binds the call back to the
same public `(object)` overload; the recursive call's `is not
NodeHandle` guard then returns false. As a result both entry points
always reported "not in view" for a validated handle, regardless of the
view. The sync variant has behaved this way since the initial commit;
the async port copied the same pattern.

The defect is latent in the SDK today: nothing calls
`INodeManager2.IsNodeInView` / `IsNodeInViewAsync` except the sync/async
adapters forwarding to each other, and Browse view filtering flows
through the protected virtuals directly. External code calling the
public API (e.g. node managers ported from the samples) was affected.

Changes:

- Both public overloads now copy the operation context
(`SystemContext.Copy(context)`) and delegate to the overridable
protected `IsNodeInView(ServerSystemContext, NodeId, NodeState)` helper
— the same virtual Browse filtering uses and sub-classes override. Doc
remarks name the virtual to override. `IsNodeInViewAsync` drops its
now-unneeded `async` keyword (signature unchanged).
- New regression test
`IsNodeInViewAsync_HandleWithNodeUsesOverridableIsNodeInViewAsync` runs
against the native async manager (both monitored-item manager
configurations) and against `CustomNodeManager2` behind
`AsyncNodeManagerAdapter`. It covers: known view → true, unknown view →
false, placeholder handle without node → false, the sync entry point via
`SyncNodeManager`, and — via an override hook on the testable managers —
that the public entry points genuinely route through the overridable
protected virtual. The test was verified to fail against the unfixed
code.
- The characterization test that locked in the broken sync behaviour
(`IsNodeInView_ValidatedHandleReturnsFalseFromPublicOverloadRecursion`,
flagged "not fixed here") is replaced by
`IsNodeInView_ValidatedHandleDelegatesToProtectedOverload`, asserting
the fixed behaviour.

Verified locally: all `IsNodeInView*` tests and the full node-manager
suites (484 tests) pass on net8.0; `Opc.Ua.Server` builds warning-free
on net472.

## Related Issues

Found while migrating the Views sample, whose view filtering uses the
protected sync virtuals and is unaffected.

- OPCFoundation/UA-.NETStandard-Samples#758

## Checklist

_Put an `x` in the boxes that apply. You can complete these step by step
after opening the PR._

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

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

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 13:59:50 +02:00
..