public ReferenceDescriptionViewModel(ReferenceDescription description, Type dataType, AccessLevelFlags accessLevel, EventNotifierFlags eventNotifier, TreeViewItemViewModel parentViewModel, Func <ReferenceDescriptionViewModel, Task> loadChildren) : base(parentViewModel, loadChildren != null) { this.description = description; this.dataType = dataType; this.accessLevel = accessLevel; this.notifier = eventNotifier; this.loadChildren = loadChildren; }
private async Task LoadChildrenAsync(ReferenceDescriptionViewModel parent) { try { var token = this.cts.Token; await [email protected](token); this.NotifyPropertyChanged("IsLoading"); try { parent.Children.Clear(); do { try { if (this.channel == null || this.channel.State != CommunicationState.Opened) { var getEndpointsRequest = new GetEndpointsRequest { EndpointUrl = this.endpointUrl, ProfileUris = new[] { TransportProfileUris.UaTcpTransport } }; var getEndpointsResponse = await UaTcpDiscoveryClient.GetEndpointsAsync(getEndpointsRequest); token.ThrowIfCancellationRequested(); var selectedEndpoint = getEndpointsResponse.Endpoints.OrderBy(e => e.SecurityLevel).First(); if (selectedEndpoint.UserIdentityTokens.Any(p => p.TokenType == UserTokenType.Anonymous)) { this.HideLoginPanel(); this.userIdentity = new AnonymousIdentity(); } else if (selectedEndpoint.UserIdentityTokens.Any(p => p.TokenType == UserTokenType.UserName)) { if (!this.showingLoginPanel) { this.ShowLoginPanel(); return; } else if (!this.ValidateLoginCredentials()) { return; } else { this.userIdentity = new UserNameIdentity(this.userName, this.password); } } else { throw new NotImplementedException("Browser supports only UserName and Anonymous identity, for now."); } dataTypeCache = new Dictionary <ExpandedNodeId, Type>(); this.channel = new UaTcpSessionChannel( this.localDescription, this.CertificateStore, this.userIdentity, selectedEndpoint); await this.channel.OpenAsync(); } token.ThrowIfCancellationRequested(); var rds = new List <ReferenceDescription>(); var browseRequest = new BrowseRequest { NodesToBrowse = new[] { new BrowseDescription { NodeId = ExpandedNodeId.ToNodeId(parent.NodeId, this.channel.NamespaceUris), ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), ResultMask = (uint)BrowseResultMask.TargetInfo, NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, BrowseDirection = BrowseDirection.Forward, IncludeSubtypes = true } } }; var browseResponse = await this.channel.BrowseAsync(browseRequest); rds.AddRange(browseResponse.Results.Where(result => result.References != null).SelectMany(result => result.References)); var continuationPoints = browseResponse.Results.Select(br => br.ContinuationPoint).Where(cp => cp != null).ToArray(); while (continuationPoints.Length > 0) { token.ThrowIfCancellationRequested(); var browseNextRequest = new BrowseNextRequest { ContinuationPoints = continuationPoints, ReleaseContinuationPoints = false }; var browseNextResponse = await this.channel.BrowseNextAsync(browseNextRequest); rds.AddRange(browseResponse.Results.Where(result => result.References != null).SelectMany(result => result.References)); } if (rds.Count == 0) { return; } foreach (var rd in rds) { token.ThrowIfCancellationRequested(); var n = ExpandedNodeId.ToNodeId(rd.NodeId, this.channel.NamespaceUris); Type dataType = null; EventNotifierFlags notifier = EventNotifierFlags.None; AccessLevelFlags accessLevel = AccessLevelFlags.None; if (rd.NodeClass == NodeClass.Variable) { var readRequest = new ReadRequest { NodesToRead = new ReadValueId[] { new ReadValueId { NodeId = n, AttributeId = AttributeIds.DataType }, new ReadValueId { NodeId = n, AttributeId = AttributeIds.ValueRank }, new ReadValueId { NodeId = n, AttributeId = AttributeIds.UserAccessLevel } } }; var readResponse = await this.channel.ReadAsync(readRequest); ExpandedNodeId dataTypeId, origDataTypeId; ReferenceDescription dataTypeRef; var dataTypeNode = readResponse.Results[0].GetValueOrDefault(NodeId.Null); if (dataTypeNode != NodeId.Null) { dataTypeId = origDataTypeId = NodeId.ToExpandedNodeId(dataTypeNode, this.channel.NamespaceUris); if (!this.dataTypeCache.TryGetValue(dataTypeId, out dataType)) { if (!UaTcpSecureChannel.DataTypeIdToTypeDictionary.TryGetValue(dataTypeId, out dataType)) { do { dataTypeNode = ExpandedNodeId.ToNodeId(dataTypeId, this.channel.NamespaceUris); var browseRequest2 = new BrowseRequest { NodesToBrowse = new[] { new BrowseDescription { NodeId = dataTypeNode, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HasSubtype), ResultMask = (uint)BrowseResultMask.None, NodeClassMask = (uint)NodeClass.DataType, BrowseDirection = BrowseDirection.Inverse, IncludeSubtypes = false } } }; var browseResponse2 = await this.channel.BrowseAsync(browseRequest2); dataTypeRef = browseResponse2.Results[0].References?.FirstOrDefault(); dataTypeId = dataTypeRef?.NodeId; }while (dataTypeId != null && !UaTcpSecureChannel.DataTypeIdToTypeDictionary.TryGetValue(dataTypeId, out dataType)); if (dataTypeId == null) { dataType = typeof(object); } } this.dataTypeCache.Add(origDataTypeId, dataType); } var valueRank = readResponse.Results[1].GetValueOrDefault(-1); if (valueRank == 1) { dataType = dataType.MakeArrayType(); } if (valueRank > 1) { dataType = dataType.MakeArrayType(valueRank); } } else { dataType = typeof(object); } accessLevel = (AccessLevelFlags)Enum.ToObject(typeof(AccessLevelFlags), readResponse.Results[2].GetValueOrDefault <byte>()); } else if (rd.NodeClass == NodeClass.Object) { var readRequest = new ReadRequest { NodesToRead = new ReadValueId[] { new ReadValueId { NodeId = n, AttributeId = AttributeIds.EventNotifier }, } }; var readResponse = await this.channel.ReadAsync(readRequest); notifier = (EventNotifierFlags)Enum.ToObject(typeof(EventNotifierFlags), readResponse.Results[0].GetValueOrDefault <byte>()); } parent.Children.Add(new ReferenceDescriptionViewModel(rd, dataType, accessLevel, notifier, parent, this.LoadChildrenAsync)); await Task.Yield(); } break; // exit while; } catch (OperationCanceledException ex) { // exit while; } catch (ServiceResultException ex) { Console.WriteLine("ServiceResultException: {0}", ex); if (this.channel != null) { await this.channel.AbortAsync(token); this.channel = null; } if (ex.HResult == unchecked ((int)StatusCodes.BadSessionIdInvalid)) { continue; } } catch (Exception ex) { Console.WriteLine("Exception {0}", ex); if (this.channel != null) { await this.channel.AbortAsync(token); this.channel = null; } } try { await Task.Delay(5000, token); } catch (OperationCanceledException) { } }while (!token.IsCancellationRequested); } catch (Exception ex) { Console.WriteLine("Exception {0}", ex); } finally { [email protected](); this.NotifyPropertyChanged("IsLoading"); } } catch (OperationCanceledException) { // only get here if cancelled while waiting for lock } }