public async Task ConnnectToEndpointsWithNoSecurityAndWithNoCertificate() { // discover available endpoints of server. var getEndpointsRequest = new GetEndpointsRequest { EndpointUrl = this.endpointUrl, ProfileUris = new[] { TransportProfileUris.UaTcpTransport } }; Console.WriteLine($"Discovering endpoints of '{getEndpointsRequest.EndpointUrl}'."); var getEndpointsResponse = await UaTcpDiscoveryClient.GetEndpointsAsync(getEndpointsRequest); // 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.SecurityMode == MessageSecurityMode.None)) { 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, null, selectedUserIdentity, selectedEndpoint, loggerFactory: this.loggerFactory); Console.WriteLine($"Creating session with endpoint '{channel.RemoteEndpoint.EndpointUrl}'."); Console.WriteLine($"SecurityPolicy: '{channel.RemoteEndpoint.SecurityPolicyUri}'."); Console.WriteLine($"SecurityMode: '{channel.RemoteEndpoint.SecurityMode}'."); Console.WriteLine($"UserIdentityToken: '{channel.UserIdentity}'."); await channel.OpenAsync(); Console.WriteLine($"Closing session '{channel.SessionId}'."); await channel.CloseAsync(); } } }
public async Task TestSubscription() { // get or add application certificate. var localCertificate = this.localDescription.GetCertificate(); if (localCertificate == null) { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Application certificate is missing."); } // discover available endpoints of server. var getEndpointsRequest = new GetEndpointsRequest { EndpointUrl = this.endpointUrl, ProfileUris = new[] { TransportProfileUris.UaTcpTransport } }; Console.WriteLine($"Discovering endpoints of '{getEndpointsRequest.EndpointUrl}'."); var getEndpointsResponse = await UaTcpDiscoveryClient.GetEndpointsAsync(getEndpointsRequest); var selectedEndpoint = getEndpointsResponse.Endpoints.OrderBy(e => e.SecurityLevel).Last(); IUserIdentity selectedUserIdentity = new UserNameIdentity("root", "secret"); var session = new UaTcpSessionClient( this.localDescription, localCertificate, selectedUserIdentity, selectedEndpoint); Console.WriteLine($"Creating session with endpoint '{session.RemoteEndpoint.EndpointUrl}'."); Console.WriteLine($"SecurityPolicy: '{session.RemoteEndpoint.SecurityPolicyUri}'."); Console.WriteLine($"SecurityMode: '{session.RemoteEndpoint.SecurityMode}'."); var sub = new MySubscription(session); Console.WriteLine($"Created subscription."); await Task.Delay(5000); session.Dispose(); Assert.IsTrue(sub.CurrentTime != DateTime.MinValue); Assert.IsTrue(sub.CurrentTimeAsDataValue != null); Assert.IsTrue(sub.CurrentTimeQueue.Count > 0); }
protected override void OnStartup(StartupEventArgs e) { // Setup a logger. this.loggerFactory = new LoggerFactory(); this.loggerFactory.AddDebug(LogLevel.Trace); // discover available endpoints of server. var getEndpointsRequest = new GetEndpointsRequest { EndpointUrl = StatusHmi.Properties.Settings.Default.EndpointUrl, ProfileUris = new[] { TransportProfileUris.UaTcpTransport } }; var getEndpointsResponse = UaTcpDiscoveryClient.GetEndpointsAsync(getEndpointsRequest).Result; var endpoint = getEndpointsResponse.Endpoints .Where(d => d.SecurityPolicyUri == SecurityPolicyUris.Basic256 && d.SecurityMode == MessageSecurityMode.SignAndEncrypt) .First(); // Create the session client for the app. this.session = new UaTcpSessionClient( new ApplicationDescription() { ApplicationName = "Workstation.StatusHmi", ApplicationUri = $"urn:{System.Net.Dns.GetHostName()}:Workstation.StatusHmi", ApplicationType = ApplicationType.Client }, new DirectoryStore( Environment.ExpandEnvironmentVariables(@"%LOCALAPPDATA%\Workstation.StatusHmi\pki"), loggerFactory: this.loggerFactory), this.ProvideUserIdentity, endpoint, this.loggerFactory); // Create the main view model. var viewModel = new MainViewModel(this.session); // Create and show the main view. var view = new MainView { DataContext = viewModel }; view.Show(); base.OnStartup(e); }
public async Task TestSubscription() { // discover available endpoints of server. var getEndpointsRequest = new GetEndpointsRequest { EndpointUrl = this.endpointUrl, ProfileUris = new[] { TransportProfileUris.UaTcpTransport } }; Console.WriteLine($"Discovering endpoints of '{getEndpointsRequest.EndpointUrl}'."); var getEndpointsResponse = await UaTcpDiscoveryClient.GetEndpointsAsync(getEndpointsRequest); var selectedEndpoint = getEndpointsResponse.Endpoints.OrderBy(e => e.SecurityLevel).Last(); var session = new UaTcpSessionClient( this.localDescription, this.certificateStore, ed => Task.FromResult <IUserIdentity>(new UserNameIdentity("root", "secret")), selectedEndpoint, loggerFactory: this.loggerFactory); Console.WriteLine($"Creating session with endpoint '{session.RemoteEndpoint.EndpointUrl}'."); Console.WriteLine($"SecurityPolicy: '{session.RemoteEndpoint.SecurityPolicyUri}'."); Console.WriteLine($"SecurityMode: '{session.RemoteEndpoint.SecurityMode}'."); var sub = new MySubscription(); session.Subscribe(sub); Console.WriteLine($"Created subscription."); await Task.Delay(5000); session.Dispose(); Assert.IsTrue(sub.CurrentTime != DateTime.MinValue, "CurrentTime"); Assert.IsTrue(sub.CurrentTimeAsDataValue != null, "CurrentTimeAsDataValue"); Assert.IsTrue(sub.CurrentTimeQueue.Count > 0, "CurrentTimeQueue"); }
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 } }
public async Task ConnnectToAllEndpoints() { // get or add application certificate. var localCertificate = this.localDescription.GetCertificate(); if (localCertificate == null) { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Application certificate is missing."); } // discover available endpoints of server. var getEndpointsRequest = new GetEndpointsRequest { EndpointUrl = this.endpointUrl, ProfileUris = new[] { TransportProfileUris.UaTcpTransport } }; Console.WriteLine($"Discovering endpoints of '{getEndpointsRequest.EndpointUrl}'."); var getEndpointsResponse = await UaTcpDiscoveryClient.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; default: selectedUserIdentity = new AnonymousIdentity(); break; } var channel = new UaTcpSessionChannel( this.localDescription, localCertificate, selectedUserIdentity, selectedEndpoint); Console.WriteLine($"Creating session with endpoint '{channel.RemoteEndpoint.EndpointUrl}'."); Console.WriteLine($"SecurityPolicy: '{channel.RemoteEndpoint.SecurityPolicyUri}'."); Console.WriteLine($"SecurityMode: '{channel.RemoteEndpoint.SecurityMode}'."); Console.WriteLine($"UserIdentityToken: '{channel.UserIdentity}'."); try { await channel.OpenAsync(); Console.WriteLine($"Closing session '{channel.SessionId}'."); await channel.CloseAsync(); } catch (Exception ex) { Console.WriteLine($"Error opening session '{channel.SessionId}'. {ex.Message}"); } } } }
public async Task TransferSubscriptions() { // get or add application certificate. var localCertificate = this.localDescription.GetCertificate(); if (localCertificate == null) { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Application certificate is missing."); } // discover available endpoints of server. var getEndpointsRequest = new GetEndpointsRequest { EndpointUrl = this.endpointUrl, ProfileUris = new[] { TransportProfileUris.UaTcpTransport } }; Console.WriteLine($"Discovering endpoints of '{getEndpointsRequest.EndpointUrl}'."); var getEndpointsResponse = await UaTcpDiscoveryClient.GetEndpointsAsync(getEndpointsRequest); var selectedEndpoint = getEndpointsResponse.Endpoints.OrderBy(e => e.SecurityLevel).Last(); IUserIdentity selectedUserIdentity = new UserNameIdentity("root", "secret"); var channel = new UaTcpSessionChannel( this.localDescription, localCertificate, selectedUserIdentity, selectedEndpoint); Console.WriteLine($"Creating session with endpoint '{channel.RemoteEndpoint.EndpointUrl}'."); Console.WriteLine($"SecurityPolicy: '{channel.RemoteEndpoint.SecurityPolicyUri}'."); Console.WriteLine($"SecurityMode: '{channel.RemoteEndpoint.SecurityMode}'."); await channel.OpenAsync(); Console.WriteLine($"Activated session '{channel.SessionId}'."); var req = new CreateSubscriptionRequest { RequestedPublishingInterval = 1000, RequestedMaxKeepAliveCount = 20, PublishingEnabled = true }; var res = await channel.CreateSubscriptionAsync(req); Console.WriteLine($"Created subscription '{res.SubscriptionId}'."); Console.WriteLine($"Aborting session '{channel.SessionId}'."); await channel.AbortAsync(); var channel2 = new UaTcpSessionChannel( this.localDescription, localCertificate, selectedUserIdentity, selectedEndpoint); await channel2.OpenAsync(); Console.WriteLine($"Activated session '{channel2.SessionId}'."); var req2 = new TransferSubscriptionsRequest { SubscriptionIds = new[] { res.SubscriptionId } }; var res2 = await channel2.TransferSubscriptionsAsync(req2); Console.WriteLine($"Transferred subscription result '{res2.Results[0].StatusCode}'."); Console.WriteLine($"Closing session '{channel2.SessionId}'."); await channel2.CloseAsync(); Assert.IsTrue(StatusCode.IsGood(res2.Results[0].StatusCode)); }
public async Task SessionTimeoutCausesFault() { // get or add application certificate. var localCertificate = this.localDescription.GetCertificate(); if (localCertificate == null) { throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Application certificate is missing."); } // discover available endpoints of server. var getEndpointsRequest = new GetEndpointsRequest { EndpointUrl = this.endpointUrl, ProfileUris = new[] { TransportProfileUris.UaTcpTransport } }; Console.WriteLine($"Discovering endpoints of '{getEndpointsRequest.EndpointUrl}'."); var getEndpointsResponse = await UaTcpDiscoveryClient.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; case UserTokenType.Certificate: selectedUserIdentity = new X509Identity(localCertificate); break; default: selectedUserIdentity = new AnonymousIdentity(); break; } var channel = new UaTcpSessionChannel( this.localDescription, localCertificate, selectedUserIdentity, selectedEndpoint, sessionTimeout: 10000); Console.WriteLine($"Creating session with endpoint '{channel.RemoteEndpoint.EndpointUrl}'."); Console.WriteLine($"SecurityPolicy: '{channel.RemoteEndpoint.SecurityPolicyUri}'."); Console.WriteLine($"SecurityMode: '{channel.RemoteEndpoint.SecurityMode}'."); await channel.OpenAsync(); 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(); }
private static async Task TestAsync() { var discoveryUrl = "opc.tcp://*****:*****@"%LOCALAPPDATA%\Workstation.ConsoleApp\pki")), userIdentity, remoteEndpoint)) { try { await session.OpenAsync(); } catch (ServiceResultException ex) { if ((uint)ex.HResult == StatusCodes.BadSecurityChecksFailed) { Console.WriteLine("Error connecting to endpoint. Did the server reject our certificate?"); } throw ex; } Console.WriteLine("Step 5 - Browse the server namespace."); Console.WriteLine("+ Root"); BrowseRequest browseRequest = new BrowseRequest { NodesToBrowse = new BrowseDescription[] { new BrowseDescription { NodeId = NodeId.Parse(ObjectIds.RootFolder), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All } }, }; BrowseResponse browseResponse = await session.BrowseAsync(browseRequest); foreach (var rd1 in browseResponse.Results[0].References ?? new ReferenceDescription[0]) { Console.WriteLine(" + {0}: {1}, {2}", rd1.DisplayName, rd1.BrowseName, rd1.NodeClass); browseRequest = new BrowseRequest { NodesToBrowse = new BrowseDescription[] { new BrowseDescription { NodeId = ExpandedNodeId.ToNodeId(rd1.NodeId, session.NamespaceUris), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All } }, }; browseResponse = await session.BrowseAsync(browseRequest); foreach (var rd2 in browseResponse.Results[0].References ?? new ReferenceDescription[0]) { Console.WriteLine(" + {0}: {1}, {2}", rd2.DisplayName, rd2.BrowseName, rd2.NodeClass); browseRequest = new BrowseRequest { NodesToBrowse = new BrowseDescription[] { new BrowseDescription { NodeId = ExpandedNodeId.ToNodeId(rd2.NodeId, session.NamespaceUris), BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = NodeId.Parse(ReferenceTypeIds.HierarchicalReferences), NodeClassMask = (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, IncludeSubtypes = true, ResultMask = (uint)BrowseResultMask.All } }, }; browseResponse = await session.BrowseAsync(browseRequest); foreach (var rd3 in browseResponse.Results[0].References ?? new ReferenceDescription[0]) { Console.WriteLine(" + {0}: {1}, {2}", rd3.DisplayName, rd3.BrowseName, rd3.NodeClass); } } } Console.WriteLine("Press any key to continue..."); Console.ReadKey(true); Console.WriteLine("Step 6 - Create a subscription."); var subscriptionRequest = new CreateSubscriptionRequest { RequestedPublishingInterval = 1000, RequestedMaxKeepAliveCount = 10, RequestedLifetimeCount = 30, PublishingEnabled = true }; var subscriptionResponse = await session.CreateSubscriptionAsync(subscriptionRequest).ConfigureAwait(false); var id = subscriptionResponse.SubscriptionId; Console.WriteLine("Step 7 - Add items to the subscription."); var itemsToCreate = new MonitoredItemCreateRequest[] { new MonitoredItemCreateRequest { ItemToMonitor = new ReadValueId { NodeId = NodeId.Parse("i=2258"), AttributeId = AttributeIds.Value }, MonitoringMode = MonitoringMode.Reporting, RequestedParameters = new MonitoringParameters { ClientHandle = 12345, SamplingInterval = -1, QueueSize = 0, DiscardOldest = true } } }; var itemsRequest = new CreateMonitoredItemsRequest { SubscriptionId = id, ItemsToCreate = itemsToCreate, }; var itemsResponse = await session.CreateMonitoredItemsAsync(itemsRequest).ConfigureAwait(false); Console.WriteLine("Step 8 - Publish the subscription."); var publishRequest = new PublishRequest { SubscriptionAcknowledgements = new SubscriptionAcknowledgement[0] }; Console.WriteLine("Press any key to delete the subscription..."); while (!Console.KeyAvailable) { var publishResponse = await session.PublishAsync(publishRequest).ConfigureAwait(false); // loop thru all the data change notifications var dcns = publishResponse.NotificationMessage.NotificationData.OfType <DataChangeNotification>(); foreach (var dcn in dcns) { foreach (var min in dcn.MonitoredItems) { Console.WriteLine($"clientHandle: {min.ClientHandle}; value: {min.Value}"); } } publishRequest = new PublishRequest { SubscriptionAcknowledgements = new[] { new SubscriptionAcknowledgement { SequenceNumber = publishResponse.NotificationMessage.SequenceNumber, SubscriptionId = publishResponse.SubscriptionId } } }; } Console.ReadKey(true); Console.WriteLine("Step 9 - Delete the subscription."); var request = new DeleteSubscriptionsRequest { SubscriptionIds = new uint[] { id } }; await session.DeleteSubscriptionsAsync(request).ConfigureAwait(false); Console.WriteLine("Press any key to close the session..."); Console.ReadKey(true); Console.WriteLine("Step 10 - Close the session."); await session.CloseAsync(); } }