/// <inheritdoc/> protected override async Task OnOpeningAsync(CancellationToken token = default) { if (RemoteEndpoint.Server == null) { // If specific endpoint is not provided, use discovery to select endpoint with highest // security level. var endpointUrl = RemoteEndpoint.EndpointUrl; var securityPolicyUri = RemoteEndpoint.SecurityPolicyUri; try { _logger?.LogInformation($"Discovering endpoints of '{endpointUrl}'."); var getEndpointsRequest = new GetEndpointsRequest { EndpointUrl = endpointUrl, ProfileUris = new[] { TransportProfileUris.UaTcpTransport } }; var getEndpointsResponse = await UaTcpDiscoveryService.GetEndpointsAsync(getEndpointsRequest, _loggerFactory).ConfigureAwait(false); if (getEndpointsResponse.Endpoints == null || getEndpointsResponse.Endpoints.Length == 0) { throw new InvalidOperationException($"'{endpointUrl}' returned no endpoints."); } var selectedEndpoint = getEndpointsResponse.Endpoints .OfType <EndpointDescription>() .Where(e => string.IsNullOrEmpty(securityPolicyUri) || e.SecurityPolicyUri == securityPolicyUri) .OrderBy(e => e.SecurityLevel) .LastOrDefault(); if (selectedEndpoint is null) { throw new InvalidOperationException($"'{endpointUrl}' returned no endpoint for the requested security policy '{securityPolicyUri}'."); } RemoteEndpoint.Server = selectedEndpoint.Server; RemoteEndpoint.ServerCertificate = selectedEndpoint.ServerCertificate; RemoteEndpoint.SecurityMode = selectedEndpoint.SecurityMode; RemoteEndpoint.SecurityPolicyUri = selectedEndpoint.SecurityPolicyUri; RemoteEndpoint.UserIdentityTokens = selectedEndpoint.UserIdentityTokens; RemoteEndpoint.TransportProfileUri = selectedEndpoint.TransportProfileUri; RemoteEndpoint.SecurityLevel = selectedEndpoint.SecurityLevel; _logger?.LogTrace($"Success discovering endpoints of '{endpointUrl}'."); } catch (Exception ex) { _logger?.LogError($"Error discovering endpoints of '{endpointUrl}'. {ex.Message}"); throw; } } // Ask for user identity. May show dialog. if (UserIdentityProvider != null) { UserIdentity = await UserIdentityProvider(RemoteEndpoint); } await base.OnOpeningAsync(token); }
public async Task SessionTimeoutCausesFault() { // discover available endpoints of server. var getEndpointsRequest = new GetEndpointsRequest { EndpointUrl = EndpointUrl, ProfileUris = new[] { TransportProfileUris.UaTcpTransport } }; Console.WriteLine($"Discovering endpoints of '{getEndpointsRequest.EndpointUrl}'."); var getEndpointsResponse = await UaTcpDiscoveryService.GetEndpointsAsync(getEndpointsRequest); var selectedEndpoint = getEndpointsResponse.Endpoints.OrderBy(e => e.SecurityLevel).Last(); var selectedTokenType = selectedEndpoint.UserIdentityTokens[0].TokenType; IUserIdentity selectedUserIdentity; switch (selectedTokenType) { case UserTokenType.UserName: selectedUserIdentity = new UserNameIdentity("root", "secret"); break; default: selectedUserIdentity = new AnonymousIdentity(); break; } var channel = new UaTcpSessionChannel( this.localDescription, this.certificateStore, selectedUserIdentity, selectedEndpoint, loggerFactory: this.loggerFactory, options: new UaTcpSessionChannelOptions { SessionTimeout = 10000 }); await channel.OpenAsync(); Console.WriteLine($"Opened session with endpoint '{channel.RemoteEndpoint.EndpointUrl}'."); Console.WriteLine($"SecurityPolicy: '{channel.RemoteEndpoint.SecurityPolicyUri}'."); Console.WriteLine($"SecurityMode: '{channel.RemoteEndpoint.SecurityMode}'."); Console.WriteLine($"Activated session '{channel.SessionId}'."); // server should close session due to inactivity await Task.Delay(20000); // should throw exception var readRequest = new ReadRequest { NodesToRead = new[] { new ReadValueId { NodeId = NodeId.Parse(VariableIds.Server_ServerStatus_CurrentTime), AttributeId = AttributeIds.Value } } }; await channel.ReadAsync(readRequest); Console.WriteLine($"Closing session '{channel.SessionId}'."); await channel.CloseAsync(); }
public async Task ConnnectToAllEndpoints() { // discover available endpoints of server. var getEndpointsRequest = new GetEndpointsRequest { EndpointUrl = EndpointUrl, ProfileUris = new[] { TransportProfileUris.UaTcpTransport } }; Console.WriteLine($"Discovering endpoints of '{getEndpointsRequest.EndpointUrl}'."); var getEndpointsResponse = await UaTcpDiscoveryService.GetEndpointsAsync(getEndpointsRequest); // for each endpoint and user identity type, try creating a session and reading a few nodes. foreach (var selectedEndpoint in getEndpointsResponse.Endpoints.OrderBy(e => e.SecurityLevel)) { foreach (var selectedTokenPolicy in selectedEndpoint.UserIdentityTokens) { IUserIdentity selectedUserIdentity; switch (selectedTokenPolicy.TokenType) { case UserTokenType.UserName: selectedUserIdentity = new UserNameIdentity("root", "secret"); break; //case UserTokenType.Certificate: // selectedUserIdentity = new X509Identity(localCertificate); // break; case UserTokenType.Anonymous: selectedUserIdentity = new AnonymousIdentity(); break; default: continue; } var channel = new UaTcpSessionChannel( this.localDescription, this.certificateStore, async e => selectedUserIdentity, selectedEndpoint, loggerFactory: this.loggerFactory, options: new UaTcpSessionChannelOptions { TimeoutHint = 60000 }); await channel.OpenAsync(); Console.WriteLine($"Opened session with endpoint '{channel.RemoteEndpoint.EndpointUrl}'."); Console.WriteLine($"SecurityPolicy: '{channel.RemoteEndpoint.SecurityPolicyUri}'."); Console.WriteLine($"SecurityMode: '{channel.RemoteEndpoint.SecurityMode}'."); Console.WriteLine($"UserIdentityToken: '{channel.UserIdentity}'."); Console.WriteLine($"Closing session '{channel.SessionId}'."); await channel.CloseAsync(); } } }
public static GetEndpointsResponse GetEndpoints(string endpoint, string port) { var temp = UaTcpDiscoveryService.GetEndpointsAsync(new GetEndpointsRequest() { EndpointUrl = "opc.tcp://" + endpoint + ":" + port }, loggerFactory); return(temp.Result); }
public static async Task <GetEndpointsResponse> GetEndpointsAsync(string endpoint, string port) { var temp = await UaTcpDiscoveryService.GetEndpointsAsync(new GetEndpointsRequest() { EndpointUrl = "opc.tcp://" + endpoint + ":" + port }, loggerFactory); return(temp); }
public async Task ConnnectToEndpointsWithNoSecurityAndWithNoCertificate() { // discover available endpoints of server. var getEndpointsRequest = new GetEndpointsRequest { EndpointUrl = EndpointUrl, ProfileUris = new[] { TransportProfileUris.UaTcpTransport } }; logger.LogInformation($"Discovering endpoints of '{getEndpointsRequest.EndpointUrl}'."); var getEndpointsResponse = await UaTcpDiscoveryService.GetEndpointsAsync(getEndpointsRequest, loggerFactory); // for each endpoint and user identity type, try creating a session and reading a few nodes. foreach (var selectedEndpoint in getEndpointsResponse.Endpoints.Where(e => e.SecurityPolicyUri == SecurityPolicyUris.None)) { foreach (var selectedTokenPolicy in selectedEndpoint.UserIdentityTokens) { IUserIdentity selectedUserIdentity; switch (selectedTokenPolicy.TokenType) { case UserTokenType.UserName: selectedUserIdentity = new UserNameIdentity("root", "secret"); break; case UserTokenType.Anonymous: selectedUserIdentity = new AnonymousIdentity(); break; default: continue; } var channel = new UaTcpSessionChannel( localDescription, null, selectedUserIdentity, selectedEndpoint, loggerFactory: loggerFactory); await channel.OpenAsync(); logger.LogInformation($"Opened session with endpoint '{channel.RemoteEndpoint.EndpointUrl}'."); logger.LogInformation($"SecurityPolicy: '{channel.RemoteEndpoint.SecurityPolicyUri}'."); logger.LogInformation($"SecurityMode: '{channel.RemoteEndpoint.SecurityMode}'."); logger.LogInformation($"UserIdentityToken: '{channel.UserIdentity}'."); logger.LogInformation($"Closing session '{channel.SessionId}'."); await channel.CloseAsync(); } } }
public IObservable <EndpointDescription[]> GetEndpoints(string url) { var request = new GetEndpointsRequest { EndpointUrl = url, }; return(Observable.FromAsync(async() => { var respones = await UaTcpDiscoveryService.GetEndpointsAsync(request); return respones .Endpoints; })); }
public static async Task ReadSubscribed(CancellationToken token = default(CancellationToken)) { { // setup logger var loggerFactory = new LoggerFactory(); loggerFactory.AddConsole(LogLevel.Information); //var logger = loggerFactory?.CreateLogger<Program>(); // Describe this app. var appDescription = new ApplicationDescription() { ApplicationName = "DataLoggingConsole", ApplicationUri = $"urn:{System.Net.Dns.GetHostName()}:DataLoggingConsole", ApplicationType = ApplicationType.Client, }; // Create a certificate store on disk. // Create array of NodeIds to log. while (!token.IsCancellationRequested) { try { // Discover endpoints. var getEndpointsRequest = new GetEndpointsRequest { EndpointUrl = discoveryUrl, ProfileUris = new[] { TransportProfileUris.UaTcpTransport } }; var getEndpointsResponse = await UaTcpDiscoveryService.GetEndpointsAsync(getEndpointsRequest) .ConfigureAwait(false); if (getEndpointsResponse.Endpoints == null || getEndpointsResponse.Endpoints.Length == 0) { throw new InvalidOperationException($"'{discoveryUrl}' returned no endpoints."); } // Choose the endpoint with highest security level. var remoteEndpoint = getEndpointsResponse.Endpoints.OrderBy(e => e.SecurityLevel).Last(); // Create a session with the server. var channel = new UaTcpSessionChannel(appDescription, certificateStore, async e => GetIUserIdentity(remoteEndpoint).GetAwaiter().GetResult(), remoteEndpoint, loggerFactory); try { await channel.OpenAsync(); var subscriptionRequest = new CreateSubscriptionRequest { RequestedPublishingInterval = 1000, RequestedMaxKeepAliveCount = 10, RequestedLifetimeCount = 30, PublishingEnabled = true }; var subscriptionResponse = await channel.CreateSubscriptionAsync(subscriptionRequest); var id = subscriptionResponse.SubscriptionId; var itemsToCreate = new MonitoredItemCreateRequest[] { #region MonitoredItems new MonitoredItemCreateRequest { ItemToMonitor = new ReadValueId { NodeId = NodeId.Parse("ns=6;s=::Program:Cube.Admin.ProdProcessedCount"), AttributeId = AttributeIds.Value }, //ProdProcessedCount MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters { ClientHandle = 1, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true } }, new MonitoredItemCreateRequest { ItemToMonitor = new ReadValueId { NodeId = NodeId.Parse("ns=6;s=::Program:Cube.Command.Parameter[0].Value"), AttributeId = AttributeIds.Value }, //Next batch ID MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters { ClientHandle = 2, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true } }, new MonitoredItemCreateRequest { ItemToMonitor = new ReadValueId { NodeId = NodeId.Parse("ns=6;s=::Program:Cube.Command.Parameter[1].Value"), AttributeId = AttributeIds.Value }, //Next product ID MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters { ClientHandle = 3, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true } }, new MonitoredItemCreateRequest { ItemToMonitor = new ReadValueId { NodeId = NodeId.Parse("ns=6;s=::Program:Cube.Command.Parameter[2].Value"), AttributeId = AttributeIds.Value }, //Amount of product in next batch MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters { ClientHandle = 4, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true } }, new MonitoredItemCreateRequest { ItemToMonitor = new ReadValueId { NodeId = NodeId.Parse("ns=6;s=::Program:Cube.Status.Parameter[2].Value"), AttributeId = AttributeIds.Value }, //Humidity MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters { ClientHandle = 5, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true } }, new MonitoredItemCreateRequest { ItemToMonitor = new ReadValueId { NodeId = NodeId.Parse("ns=6;s=::Program:Cube.Status.Parameter[3].Value"), AttributeId = AttributeIds.Value }, //Temperature MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters { ClientHandle = 6, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true } }, new MonitoredItemCreateRequest { ItemToMonitor = new ReadValueId { NodeId = NodeId.Parse("ns=6;s=::Program:Cube.Status.Parameter[4].Value"), AttributeId = AttributeIds.Value }, //Vibration MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters { ClientHandle = 7, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true } }, new MonitoredItemCreateRequest { ItemToMonitor = new ReadValueId { NodeId = NodeId.Parse("ns=6;s=::Program:Cube.Status.MachSpeed"), AttributeId = AttributeIds.Value }, //MachineSpeed MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters { ClientHandle = 8, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true } }, new MonitoredItemCreateRequest { ItemToMonitor = new ReadValueId { NodeId = NodeId.Parse("ns=6;s=::Program:Cube.Status.StateCurrent"), AttributeId = AttributeIds.Value }, //state MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters { ClientHandle = 9, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true } }, new MonitoredItemCreateRequest { ItemToMonitor = new ReadValueId { NodeId = NodeId.Parse("ns=6;s=::Program:Cube.Status.StateCurrent"), AttributeId = AttributeIds.Value }, //cmdCtrln MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters { ClientHandle = 10, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true } } #endregion }; var itemsRequest = new CreateMonitoredItemsRequest { SubscriptionId = id, ItemsToCreate = itemsToCreate, }; var itemsResponse = await channel.CreateMonitoredItemsAsync(itemsRequest); var subToken = channel.Where(pr => pr.SubscriptionId == id).Subscribe(pr => { // loop through all the data change notifications var dcns = pr.NotificationMessage.NotificationData.OfType <DataChangeNotification>(); foreach (var dcn in dcns) { foreach (var min in dcn.MonitoredItems) { switch (min.ClientHandle) { case 1: prodProc = (int)min.Value.Value; time = (DateTime)min.Value.ServerTimestamp; break; case 2: time = (DateTime)min.Value.ServerTimestamp; nextBatchID = (float)min.Value.Value; break; case 3: time = (DateTime)min.Value.ServerTimestamp; nextProductID = (float)min.Value.Value; break; case 4: time = (DateTime)min.Value.ServerTimestamp; nextProductAmount = (float)min.Value.Value; break; case 5: time = (DateTime)min.Value.ServerTimestamp; humidity = (float)min.Value.Value; break; case 6: time = (DateTime)min.Value.ServerTimestamp; temperature = (float)min.Value.Value; break; case 7: time = (DateTime)min.Value.ServerTimestamp; vibration = (float)min.Value.Value; break; case 8: time = (DateTime)min.Value.ServerTimestamp; machinespeed = (float)min.Value.Value; break; case 9: time = (DateTime)min.Value.ServerTimestamp; State = (int)min.Value.Value; break; case 10: cmdctrl = (int)min.Value.Value; time = (DateTime)min.Value.ServerTimestamp; break; } } } }); while (!token.IsCancellationRequested) { await Task.Delay(500); } } catch { } } catch (Exception ex) { } //try //{ // await Task.Delay(cycleTime, token); //} //catch //{ //} } } }
private static async Task Write(List <NodeId> nodesIds, DataValue dataval) { // setup logger var loggerFactory = new LoggerFactory(); loggerFactory.AddDebug(LogLevel.Debug); // Describe this app. var appDescription = new ApplicationDescription() { ApplicationName = "DataLoggingConsole", ApplicationUri = $"urn:{System.Net.Dns.GetHostName()}:DataLoggingConsole", ApplicationType = ApplicationType.Client, }; // Create a certificate store on disk. // Create array of NodeIds to log. var nodeIds = nodesIds.ToArray(); try { // Discover endpoints. var getEndpointsRequest = new GetEndpointsRequest { EndpointUrl = discoveryUrl, ProfileUris = new[] { TransportProfileUris.UaTcpTransport } }; var getEndpointsResponse = await UaTcpDiscoveryService.GetEndpointsAsync(getEndpointsRequest).ConfigureAwait(false); if (getEndpointsResponse.Endpoints == null || getEndpointsResponse.Endpoints.Length == 0) { throw new InvalidOperationException($"'{discoveryUrl}' returned no endpoints."); } // Choose the endpoint with highest security level. var remoteEndpoint = getEndpointsResponse.Endpoints.OrderBy(e => e.SecurityLevel).Last(); // Create a session with the server. var session = new UaTcpSessionChannel(appDescription, certificateStore, async e => GetIUserIdentity(remoteEndpoint).GetAwaiter().GetResult(), remoteEndpoint, loggerFactory); try { await session.OpenAsync(); RegisterNodesResponse registerNodesResponse = null; if (true) // True registers the nodeIds to improve performance of the server. { // Register array of nodes to read. var registerNodesRequest = new RegisterNodesRequest { NodesToRegister = nodeIds }; registerNodesResponse = await session.RegisterNodesAsync(registerNodesRequest); } WriteRequest writeRequest = new WriteRequest(); writeRequest.NodesToWrite = new WriteValue[1] { new WriteValue() { NodeId = nodeIds[0], AttributeId = AttributeIds.Value, Value = dataval } }; WriteRequest request = writeRequest; StatusCode statusCode; // write the nodes. statusCode = (await session.WriteAsync(request).ConfigureAwait(false)).Results[0];; } catch { await session.AbortAsync(); throw; } await session.AbortAsync(); } catch (Exception e) { // ignored } }
private async Task <bool> TryConnect() { if (connection != null) { return(true); } if (string.IsNullOrEmpty(config.Address)) { return(false); } try { var getEndpointsRequest = new GetEndpointsRequest { EndpointUrl = config.Address, ProfileUris = new[] { TransportProfileUris.UaTcpTransport } }; GetEndpointsResponse endpoints = await UaTcpDiscoveryService.GetEndpointsAsync(getEndpointsRequest); EndpointDescription[] noSecurityEndpoints = endpoints.Endpoints.Where(e => e.SecurityPolicyUri == SecurityPolicyUris.None).ToArray(); var(endpoint, userIdentity) = FirstEndpointWithLogin(noSecurityEndpoints); if (endpoint == null || userIdentity == null) { throw new Exception("No matching endpoint"); } var channel = new UaTcpSessionChannel( this.appDescription, null, userIdentity, endpoint, loggerFactory); await channel.OpenAsync(); this.connection = channel; PrintLine($"Opened session with endpoint '{channel.RemoteEndpoint.EndpointUrl}'."); PrintLine($"SecurityPolicy: '{channel.RemoteEndpoint.SecurityPolicyUri}'."); PrintLine($"SecurityMode: '{channel.RemoteEndpoint.SecurityMode}'."); PrintLine($"UserIdentityToken: '{channel.UserIdentity}'."); ItemInfo[] nodesNeedingResolve = mapId2Info.Values.Where(n => n.Node == null).ToArray(); if (nodesNeedingResolve.Length > 0) { PrintLine($"Resolving node ids for {nodesNeedingResolve.Length} items..."); TranslateBrowsePathsToNodeIdsRequest req = new TranslateBrowsePathsToNodeIdsRequest() { BrowsePaths = nodesNeedingResolve.Select(n => new BrowsePath() { StartingNode = n.StartingNode, RelativePath = n.RelativePath }).ToArray() }; TranslateBrowsePathsToNodeIdsResponse resp = await connection.TranslateBrowsePathsToNodeIdsAsync(req); if (resp.Results.Length != nodesNeedingResolve.Length) { LogWarn("Mismatch", "TranslateBrowsePathsToNodeIds failed"); } else { for (int i = 0; i < resp.Results.Length; ++i) { BrowsePathResult x = resp.Results[i]; if (StatusCode.IsGood(x.StatusCode) && x.Targets.Length > 0) { NodeId id = x.Targets[0].TargetId.NodeId; nodesNeedingResolve[i].Node = id; PrintLine($"Resolved item '{nodesNeedingResolve[i].Name}' => {id}"); } else { PrintLine($"Could not resolve item '{nodesNeedingResolve[i].Name}'!"); } } } } return(true); } catch (Exception exp) { Exception baseExp = exp.GetBaseException() ?? exp; LogWarn("OpenChannel", "Open channel error: " + baseExp.Message, dataItem: null, details: baseExp.StackTrace); await CloseChannel(); return(false); } }
private static async Task TestAsync(CancellationToken token = default(CancellationToken)) { var discoveryUrl = $"opc.tcp://localhost:26543"; var cycleTime = 5000; // setup logger var loggerFactory = new LoggerFactory(); loggerFactory.AddConsole(LogLevel.Information); var logger = loggerFactory?.CreateLogger <Program>(); // Describe this app. var appDescription = new ApplicationDescription() { ApplicationName = "DataLoggingConsole", ApplicationUri = $"urn:{System.Net.Dns.GetHostName()}:DataLoggingConsole", ApplicationType = ApplicationType.Client, }; // Create a certificate store on disk. var certificateStore = new DirectoryStore( Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "DataLoggingConsole", "pki")); // Create array of NodeIds to log. var nodeIds = new[] { NodeId.Parse("i=2258") }; while (!token.IsCancellationRequested) { try { // Discover endpoints. var getEndpointsRequest = new GetEndpointsRequest { EndpointUrl = discoveryUrl, ProfileUris = new[] { TransportProfileUris.UaTcpTransport } }; var getEndpointsResponse = await UaTcpDiscoveryService.GetEndpointsAsync(getEndpointsRequest).ConfigureAwait(false); if (getEndpointsResponse.Endpoints == null || getEndpointsResponse.Endpoints.Length == 0) { throw new InvalidOperationException($"'{discoveryUrl}' returned no endpoints."); } // Choose the endpoint with highest security level. var remoteEndpoint = getEndpointsResponse.Endpoints.OrderBy(e => e.SecurityLevel).Last(); // Choose a User Identity. IUserIdentity userIdentity = null; if (remoteEndpoint.UserIdentityTokens.Any(p => p.TokenType == UserTokenType.Anonymous)) { userIdentity = new AnonymousIdentity(); } else if (remoteEndpoint.UserIdentityTokens.Any(p => p.TokenType == UserTokenType.UserName)) { // If a username / password is requested, provide from .config file. userIdentity = new UserNameIdentity("root", "secret"); } else { throw new InvalidOperationException("Server must accept Anonymous or UserName identity."); } // Create a session with the server. var session = new UaTcpSessionChannel(appDescription, certificateStore, async e => userIdentity, remoteEndpoint, loggerFactory); try { await session.OpenAsync(); RegisterNodesResponse registerNodesResponse = null; if (true) // True registers the nodeIds to improve performance of the server. { // Register array of nodes to read. var registerNodesRequest = new RegisterNodesRequest { NodesToRegister = nodeIds }; registerNodesResponse = await session.RegisterNodesAsync(registerNodesRequest); } // Prepare read request. var readRequest = new ReadRequest { NodesToRead = (registerNodesResponse?.RegisteredNodeIds ?? nodeIds) .Select(n => new ReadValueId { NodeId = n, AttributeId = AttributeIds.Value }) .ToArray() }; while (!token.IsCancellationRequested) { // Read the nodes. var readResponse = await session.ReadAsync(readRequest).ConfigureAwait(false); // Write the results. for (int i = 0; i < readRequest.NodesToRead.Length; i++) { logger?.LogInformation($"{nodeIds[i]}; value: {readResponse.Results[i]}"); } try { await Task.Delay(cycleTime, token); } catch { } } await session.CloseAsync(); } catch { await session.AbortAsync(); throw; } } catch (Exception ex) { logger?.LogError(ex.Message); } try { await Task.Delay(cycleTime, token); } catch { } } }