OPCFoundation / UA-.NETStandard

OPC Unified Architecture .NET Standard
Other
1.9k stars 926 forks source link

Browse populates Names while BrowseAsync does not #2498

Closed RFBomb closed 5 months ago

RFBomb commented 5 months ago

Type of issue

Current Behavior

I am testing Browse vs BrowseAsync in my app, and I can not use BrowseAsync, as the result are not equivalent between the two. Specifically, the ReferenceDescriptionCollection returned from the Browse method has the browse names populates, while the BrowseAsync does not populate those names in the returned collection.

Browse image

BrowseAsync image

Browse image

BrowseAsync image

Expected Behavior

The names would be populated in both returned collections. I also note that the IsForward property on the result returned from browse is true, while its false on the async object

Steps To Reproduce

My understanding is that these should be functionally identical

var browseResponse = await session.BrowseAsync(null, null, 0u, ct: ct,
    nodesToBrowse: new BrowseDescriptionCollection() { new BrowseDescription() {
        NodeId = robotSharedApi,
        BrowseDirection = BrowseDirection.Forward,
        IncludeSubtypes = true, 
        NodeClassMask = (uint)(NodeClass.Variable | NodeClass.Object | NodeClass.Method),
        ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences
    }
    });

session.Browse(
    null,
    null,
    robotSharedApi,
    0u,
    BrowseDirection.Forward,
    ReferenceTypeIds.HierarchicalReferences,
    true,
    (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method,
    out var continuationPoint,
    out var references);

Environment

- OS: Windows 10 64bit
- Environment: Visual Studio 2019
- Runtime: .NetStandard
- Nuget Version: 1.5.372.113
- Component: Session.Browse
- Server: n/a
- Client: n/a

Anything else?

No response

ThomasNehring commented 5 months ago

Session.Browse() is a wrapper for SessionClientBatched.Browse(). It adds the setting

ResultMask = (uint)BrowseResultMask.All

to the browse descriptions before calling SessionClientBatched.Browse()

The call in your question to BrowseAsync seems to be (according to the parameters you have set) a direct call to SessionClientBatched.BrowseAsync or even SessionClient.BrowseAsync, but the BrowseDescription you are providing does not set the ResultMask. In this case the ResultMask defaults to 0 (None). The async equivalent to Browse would be SessionAsync.BrowseAsync, to my understanding. Can you please try again with the BrowseResultMask set?

RFBomb commented 5 months ago

I won't be able to try this out until next week most likely.

But that begs the question, why is the result mask set in one and not the other? I understand that for the Async call you must manually build the BrowseDescription object, but if that option is omitted I would expect the behavior to be identical, as the other one doesn't explicitly declare it in my usage either. Seems like an oversight.

ThomasNehring commented 5 months ago

No, it's not an oversight. The one(s) which populate(s) the browse result mask is/are in the client library, which provides convenience functions for the developer, the other one is/are in the UA core, which usually just implements the service calls as required by the spec.

RFBomb commented 5 months ago

Understood.

As a temporary measure I had created my own method extension to run the Browse as Async via Task.Run, now I'm aware of the nuance and that it's intentional I'll modify that to build it properly using the mask. Thanks for the response.

Im good with closing this topic unless your team wanted it open as reference.

ThomasNehring commented 5 months ago

I'll wait with closing this till our next internal call tomorrow when I will try to discuss this.

ThomasNehring commented 5 months ago

We discussed this in the weekly meeting. While we agreed that it is not nice that the generated functions from the UA core are easily mixed up with the API functionality, we will not change anything on short notice.

So I will in fact now close this topic.