Пример #1
0
 /// <summary>
 /// Constrcutor to initiate the reflective filter's 'filtering' operation.
 ///
 /// object type of holding property value
 /// the type of collection to add the object back into if filtered
 /// the optional clause of == or != to
 /// the FilterPropertiesCollection that contains /// all of the property names and values that we need to match
 ///
 /// the filter operand. Either an OR or AND
 /// </summary>
 public FilterOperation(Type typeOfObject, Type typeOfCollection, FilterClause clause, FilterPropertyCollection propertiesAndValues, FilterOperand operand)
 {
     _ObjectType          = typeOfObject;
     _CollectionType      = typeOfCollection;
     _FilterClause        = clause;
     _PropertiesAndValues = propertiesAndValues;
     _Operand             = operand;
 }
Пример #2
0
        private FilterOperand GetLhs(FilterParser.Elem_opContext elem_opContext)
        {
            FilterOperand lhs = Evaluate(elem_opContext.elem_op()?[0]);

            if (lhs == null)
            {
                lhs = Evaluate(elem_opContext.attr_op().First());
            }
            return(lhs);
        }
        /// <see cref="BaseListCtrl.UpdateItem" />
        protected override void UpdateItem(ListViewItem listItem, object item, int index)
        {
            FilterOperand operand = item as FilterOperand;

            if (operand == null)
            {
                base.UpdateItem(listItem, item);
                return;
            }

            listItem.SubItems[0].Text = String.Format("[{0}]", index);
            listItem.SubItems[1].Text = operand.ToString(m_session.NodeCache);

            listItem.Tag = operand;
        }
        /// <summary>
        /// Returns the list of operands in the control.
        /// </summary>
        public List <FilterOperand> GetOperands()
        {
            List <FilterOperand> operands = new List <FilterOperand>();

            for (int ii = 0; ii < ItemsLV.Items.Count; ii++)
            {
                FilterOperand operand = ItemsLV.Items[ii].Tag as FilterOperand;

                if (operand != null)
                {
                    operands.Add(operand);
                }
            }

            return(operands);
        }
Пример #5
0
 public ReflectiveFilter(Type typeOfObject, Type typeOfCollection, FilterOperand operand)
 {
     _FilterList     = new FilterPropertyCollection();
     _ObjectType     = typeOfObject;
     _CollectionType = typeOfCollection;
     _Operand        = operand;
     try
     {
         // create the concrete collection type
         _FilteredCollection = (IList)Activator.CreateInstance(_CollectionType);
     }
     catch (System.MemberAccessException)
     {
         throw new MemberAccessException("You must specify a collection that is not abstract");
     }
 }
Пример #6
0
        private FilterOperand GetRhs(FilterParser.Elem_opContext elem_opContext)
        {
            FilterOperand rhs = Evaluate(elem_opContext.lit_op());

            if (rhs == null)
            {
                rhs = Evaluate(elem_opContext.attr_op().Last());
            }
            if (rhs == null)
            {
                var elem = elem_opContext.elem_op();
                if (elem?.Length == 2)
                {
                    rhs = Evaluate(elem_opContext.elem_op()?[1]);
                }
            }
            return(rhs);
        }
        /// <summary>
        /// Convert to service model
        /// </summary>
        /// <param name="model"></param>
        /// <param name="encoder"></param>
        /// <returns></returns>
        public static FilterOperandModel Encode(this IVariantEncoder encoder,
                                                FilterOperand model)
        {
            if (model == null)
            {
                return(null);
            }
            switch (model)
            {
            case ElementOperand elem:
                return(new FilterOperandModel {
                    Index = elem.Index
                });

            case LiteralOperand lit:
                return(new FilterOperandModel {
                    Value = encoder.Encode(lit.Value, out _)
                });

            case AttributeOperand attr:
                return(new FilterOperandModel {
                    NodeId = attr.NodeId.AsString(encoder.Context),
                    AttributeId = (NodeAttribute)attr.AttributeId,
                    BrowsePath = attr.BrowsePath.AsString(encoder.Context),
                    IndexRange = attr.IndexRange,
                    Alias = attr.Alias
                });

            case SimpleAttributeOperand sattr:
                return(new FilterOperandModel {
                    NodeId = sattr.TypeDefinitionId.AsString(encoder.Context),
                    AttributeId = (NodeAttribute)sattr.AttributeId,
                    BrowsePath = sattr.BrowsePath?
                                 .Select(p => p.AsString(encoder.Context))
                                 .ToArray(),
                    IndexRange = sattr.IndexRange
                });

            default:
                throw new NotSupportedException("Operand not supported");
            }
        }
        public static string GetSqlOperation(this FilterOperand operand)
        {
            switch (operand)
            {
            case FilterOperand.GreaterThan:
                return(">");

            case FilterOperand.GreaterThanEqual:
                return(">=");

            case FilterOperand.LessThan:
                return("<");

            case FilterOperand.LessThanEqual:
                return("<=");

            case FilterOperand.Equals:
                return("=");

            default:
                return("=");
            }
        }
Пример #9
0
 public QueryFilter(string fieldName, FilterOperand operand, string value)
 {
     this._fieldName = fieldName;
     this._operand   = operand;
     this._value     = value;
 }
Пример #10
0
        /// <summary>
        /// Displays the dialog.
        /// </summary>
        public FilterOperand ShowDialog(
            Session session,
            IList <ContentFilterElement> elements,
            int index,
            FilterOperand operand)
        {
            if (session == null)
            {
                throw new ArgumentNullException("session");
            }
            if (elements == null)
            {
                throw new ArgumentNullException("elements");
            }

            m_session = session;

            TypeDefinitionIdCTRL.Browser = new Browser(session);
            TypeDefinitionIdCTRL.RootId  = ObjectTypes.BaseEventType;

            OperandTypeCB.SelectedItem = typeof(LiteralOperand).Name;

            if (operand != null)
            {
                OperandTypeCB.SelectedItem = operand.GetType().Name;
            }

            ElementsCB.Items.Clear();

            for (int ii = index + 1; ii < elements.Count; ii++)
            {
                ElementsCB.Items.Add(elements[ii].ToString(m_session.NodeCache));
            }

            ElementOperand elementOperand = operand as ElementOperand;

            if (elementOperand != null)
            {
                ElementsCB.SelectedIndex = (int)elementOperand.Index - index - 1;
            }

            AttributeOperand attributeOperand = operand as AttributeOperand;

            if (attributeOperand != null)
            {
                TypeDefinitionIdCTRL.Identifier = attributeOperand.NodeId;
                BrowsePathTB.Text          = attributeOperand.BrowsePath.Format(session.NodeCache.TypeTree);
                AttributeIdCB.SelectedItem = Attributes.GetBrowseName(attributeOperand.AttributeId);
                IndexRangeTB.Text          = attributeOperand.IndexRange;
                AliasTB.Text = attributeOperand.Alias;
            }

            LiteralOperand literalOperand = operand as LiteralOperand;

            if (literalOperand != null)
            {
                NodeId datatypeId = TypeInfo.GetDataTypeId(literalOperand.Value.Value);
                DataTypeCB.SelectedItem = TypeInfo.GetBuiltInType(datatypeId);

                StringBuilder buffer = new StringBuilder();

                Array array = literalOperand.Value.Value as Array;

                if (array != null)
                {
                    for (int ii = 0; ii < array.Length; ii++)
                    {
                        if (ii > 0)
                        {
                            buffer.Append("\r\n");
                        }

                        buffer.AppendFormat("{0}", new Variant(array.GetValue(ii)));
                    }
                }
                else
                {
                    buffer.AppendFormat("{0}", literalOperand.Value);
                }

                ValueTB.Text = buffer.ToString();
            }

            if (ShowDialog() != DialogResult.OK)
            {
                return(null);
            }

            return(operand);
        }
		/// <summary>
		/// Applys the filter.
		/// </summary>
		/// <param name="property">Property.</param>
		/// <param name="compareValue">Compare value.</param>
		public void ApplyFilter(string property, object compareValue, FilterOperand operand) 
		{ 
			PropertyDescriptor filterBy = GetPropertyDescriptor(property); 
			
			filteredList = new ArrayList();

			foreach (object obj in baseList) 
			{ 
				switch (operand)
				{
					case FilterOperand.Equals:
					{
						if(filterBy.GetValue(obj).Equals(compareValue))	filteredList.Add(obj);
						break;
					}
					case FilterOperand.NotEquals:
					{
						if(!(filterBy.GetValue(obj).Equals(compareValue)))	filteredList.Add(obj);
						break;
					}
				}
			} 

			isFiltered = true; 

			if(ListChanged != null) 
			{ 
				ListChanged(this, new ListChangedEventArgs(ListChangedType.Reset, 0)); 
			} 
		}
Пример #12
0
        /// <summary>
        /// Displays the dialog.
        /// </summary>
        public FilterOperand ShowDialog(
            Session                     session, 
            IList<ContentFilterElement> elements, 
            int                         index, 
            FilterOperand               operand)
        {
            if (session == null)  throw new ArgumentNullException("session");
            if (elements == null) throw new ArgumentNullException("elements");

            m_session = session;
            
            TypeDefinitionIdCTRL.Browser = new Browser(session);
            TypeDefinitionIdCTRL.RootId  = ObjectTypes.BaseEventType;

            OperandTypeCB.SelectedItem = typeof(LiteralOperand).Name;

            if (operand != null)
            {
                OperandTypeCB.SelectedItem = operand.GetType().Name;
            }
            
            ElementsCB.Items.Clear();

            for (int ii = index+1; ii < elements.Count; ii++)
            {
                ElementsCB.Items.Add(elements[ii].ToString(m_session.NodeCache));
            }
                        
            ElementOperand elementOperand = operand as ElementOperand;

            if (elementOperand != null)
            {
                ElementsCB.SelectedIndex = (int)elementOperand.Index - index -1;
            }
            
            AttributeOperand attributeOperand = operand as AttributeOperand;

            if (attributeOperand != null)
            {
                TypeDefinitionIdCTRL.Identifier = attributeOperand.NodeId;
                BrowsePathTB.Text               = attributeOperand.BrowsePath.Format(session.NodeCache.TypeTree);
                AttributeIdCB.SelectedItem      = Attributes.GetBrowseName(attributeOperand.AttributeId);
                IndexRangeTB.Text               = attributeOperand.IndexRange;
                AliasTB.Text                    = attributeOperand.Alias;
            }
            
            LiteralOperand literalOperand = operand as LiteralOperand;

            if (literalOperand != null)
            {
                NodeId datatypeId = TypeInfo.GetDataTypeId(literalOperand.Value.Value);
                DataTypeCB.SelectedItem = TypeInfo.GetBuiltInType(datatypeId);

                StringBuilder buffer = new StringBuilder();

                Array array = literalOperand.Value.Value as Array;

                if (array != null)
                {
                    for (int ii = 0; ii < array.Length; ii++)
                    {
                        if (ii > 0)
                        {
                            buffer.Append("\r\n");
                        }

                        buffer.AppendFormat("{0}", new Variant(array.GetValue(ii)));
                    }
                }
                else
                {
                    buffer.AppendFormat("{0}", literalOperand.Value);
                }

                ValueTB.Text = buffer.ToString();
            }
                        
            if (ShowDialog() != DialogResult.OK)
            {
                return null;
            }

            return operand;
        }
        String BuildFilterCondition(FilterOperationBase filter)
        {
            StringBuilder builder = new StringBuilder();

            if (filter != null)
            {
                // Опрерация
                FilterOperation operation = filter as FilterOperation;
                if (operation != null)
                {
                    List <String> operands = new List <string>();
                    foreach (FilterOperationBase child in operation.Children)
                    {
                        String x = BuildFilterCondition(child);
                        if (!String.IsNullOrEmpty(x))
                        {
                            operands.Add(String.Format("({0})", x));
                        }
                    }

                    if (operands.Count > 1)
                    {
                        builder.Append("(");
                    }
                    for (int i = 0; i < operands.Count; i++)
                    {
                        if (i > 0)
                        {
                            builder.AppendFormat(" {0} ", operation.Operation.ToString());
                        }
                        builder.Append(operands[i]);
                    }
                    if (operands.Count > 1)
                    {
                        builder.Append(")");
                    }
                }

                FilterOperand operand = filter as FilterOperand;
                if (operand != null)
                {
                    // Если свойство не является общим для всех уровней - (общие: Caption, UniqueName, Name)
                    // То при формировании нужно обязательно проверять чтобы текущий уровень был именно тем, на котором это свойство есть
                    // Исключение составляют случаи когда измерение Parent-Child
                    bool isParentChild = false;
                    // XXX
                    //try
                    //{
                    //    OlapMetadataProvider provider = new OlapMetadataProvider(QueryExecuter.Connection);
                    //    HierarchyInfo hierarchy = provider.GetHierarchy(cubeName, String.Empty, hierarchyUniqueName);
                    //    if(hierarchy != null && hierarchy.HierarchyOrigin == HierarchyInfoOrigin.ParentChildHierarchy)
                    //    {
                    //        isParentChild = true;
                    //    }
                    //}
                    //catch { }

                    // Свойство с одним и тем же именем может присутствовать на нескольких уровнях. В данном случае operand.PropertyLevels содержит коллекцию уникальных имен уровней. Их все нужно учесть
                    if (operand.PropertyLevels.Count != 0 && !isParentChild)
                    {
                        int i = 0;
                        builder.Append("(");
                        foreach (String levelUniqueName in operand.PropertyLevels)
                        {
                            if (i > 0)
                            {
                                builder.Append("or ");
                            }
                            builder.AppendFormat("({0}.Level is {1}) ", HierarchyUniqueName, levelUniqueName);
                            i++;
                        }
                        builder.Append(")");
                        builder.Append(" and ");
                    }
                    switch (operand.Condition)
                    {
                    case ConditionTypes.Equal:
                        builder.AppendFormat("{0}.Properties(\"{1}\")='{2}'", HierarchyUniqueName, operand.Property, operand.Value);
                        break;

                    case ConditionTypes.Contains:
                        builder.AppendFormat("InStr({0}.Properties(\"{1}\"),'{2}') <> 0", HierarchyUniqueName, operand.Property, operand.Value);
                        break;

                    case ConditionTypes.BeginWith:
                        //Позиция при использовании InStr начинается с 1
                        builder.AppendFormat("InStr({0}.Properties(\"{1}\"),'{2}') = 1", HierarchyUniqueName, operand.Property, operand.Value);
                        break;
                    }
                }
            }
            return(builder.ToString());
        }
Пример #14
0
        /// <summary>
        /// Monitoring for an event source starts if it is required.
        /// </summary>
        public async Task MonitorEventsAsync(CancellationToken ct)
        {
            bool sessionLocked = false;

            try
            {
                try
                {
                    sessionLocked = await LockSessionAsync().ConfigureAwait(false);

                    // if the session is not connected or shutdown in progress, return
                    if (!sessionLocked || ct.IsCancellationRequested || State != SessionState.Connected)
                    {
                        return;
                    }
                }
                catch (Exception)
                {
                    throw;
                }

                // ensure all nodes in all subscriptions of this session are monitored.
                foreach (var opcEventSubscription in OpcEventSubscriptions)
                {
                    // create the subscription, if it is not yet there.
                    if (opcEventSubscription.OpcUaClientSubscription == null)
                    {
                        opcEventSubscription.OpcUaClientSubscription = CreateSubscription(opcEventSubscription.RequestedPublishingInterval, out int revisedPublishingInterval);
                        opcEventSubscription.PublishingInterval      = revisedPublishingInterval;
                        Logger.Information($"Create Event subscription on endpoint '{EndpointUrl}' requested OPC publishing interval is {opcEventSubscription.RequestedPublishingInterval} ms. (revised: {revisedPublishingInterval} ms)");
                    }

                    // process all unmonitored events.
                    var  unmonitoredEvents = opcEventSubscription.OpcMonitoredItems.Where(i => (i.State == OpcMonitoredItemState.Unmonitored || i.State == OpcMonitoredItemState.UnmonitoredNamespaceUpdateRequested));
                    int  additionalMonitoredEventsCount = 0;
                    int  monitoredEventsCount           = 0;
                    bool haveUnmonitoredEvents          = false;
                    if (unmonitoredEvents.Count() != 0)
                    {
                        haveUnmonitoredEvents = true;
                        monitoredEventsCount  = opcEventSubscription.OpcMonitoredItems.Count(i => (i.State == OpcMonitoredItemState.Monitored));
                        Logger.Information($"Start monitoring events on endpoint '{EndpointUrl}'. Currently monitoring {monitoredEventsCount} events.");
                    }

                    // init perf data
                    Stopwatch stopWatch = new Stopwatch();
                    stopWatch.Start();
                    foreach (var unmonitoredEvent in unmonitoredEvents)
                    {
                        // if the session is not connected or a shutdown is in progress, we stop trying and wait for the next cycle
                        if (ct.IsCancellationRequested || State != SessionState.Connected)
                        {
                            break;
                        }

                        NodeId currentNodeId = null;
                        try
                        {
                            // update the namespace of the node if requested. there are two cases where this is requested:
                            // 1) publishing requests via the OPC server method are raised using a NodeId format. for those
                            //    the NodeId format is converted into an ExpandedNodeId format
                            // 2) ExpandedNodeId configuration file entries do not have at parsing time a session to get
                            //    the namespace index. this is set now.
                            if (unmonitoredEvent.State == OpcMonitoredItemState.UnmonitoredNamespaceUpdateRequested)
                            {
                                if (unmonitoredEvent.ConfigType == OpcMonitoredItemConfigurationType.ExpandedNodeId)
                                {
                                    ExpandedNodeId expandedNodeId = ExpandedNodeId.Parse(unmonitoredEvent.Id);
                                    int            namespaceIndex = _namespaceTable.GetIndex(expandedNodeId.NamespaceUri);
                                    if (namespaceIndex < 0)
                                    {
                                        Logger.Information($"The namespace URI of node '{expandedNodeId.ToString()}' can be not mapped to a namespace index.");
                                    }
                                    else
                                    {
                                        unmonitoredEvent.IdAsExpandedNodeId = expandedNodeId;
                                    }
                                }
                                if (unmonitoredEvent.ConfigType == OpcMonitoredItemConfigurationType.NodeId)
                                {
                                    NodeId nodeId       = NodeId.Parse(unmonitoredEvent.Id);
                                    string namespaceUri = _namespaceTable.ToArray().ElementAtOrDefault(nodeId.NamespaceIndex);
                                    if (string.IsNullOrEmpty(namespaceUri))
                                    {
                                        Logger.Information($"The namespace index of node '{nodeId.ToString()}' is invalid and the node format can not be updated.");
                                    }
                                    else
                                    {
                                        unmonitoredEvent.IdAsExpandedNodeId = new ExpandedNodeId(nodeId.Identifier, nodeId.NamespaceIndex, namespaceUri, 0);
                                        unmonitoredEvent.ConfigType         = OpcMonitoredItemConfigurationType.ExpandedNodeId;
                                    }
                                }
                                unmonitoredEvent.State = OpcMonitoredItemState.Unmonitored;
                            }

                            // lookup namespace index if ExpandedNodeId format has been used and build NodeId identifier.
                            if (unmonitoredEvent.ConfigType == OpcMonitoredItemConfigurationType.ExpandedNodeId)
                            {
                                ExpandedNodeId expandedNodeId = ExpandedNodeId.Parse(unmonitoredEvent.Id);
                                int            namespaceIndex = _namespaceTable.GetIndex(expandedNodeId.NamespaceUri);
                                if (namespaceIndex < 0)
                                {
                                    Logger.Warning($"Syntax or namespace URI of ExpandedNodeId '{expandedNodeId.ToString()}' is invalid and will be ignored.");
                                    continue;
                                }
                                unmonitoredEvent.IdAsNodeId = new NodeId(expandedNodeId.Identifier, expandedNodeId.NamespaceIndex);
                                currentNodeId = unmonitoredEvent.IdAsNodeId;
                            }
                            else
                            {
                                NodeId nodeId       = NodeId.Parse(unmonitoredEvent.Id);
                                string namespaceUri = _namespaceTable.ToArray().ElementAtOrDefault(nodeId.NamespaceIndex);
                                if (string.IsNullOrEmpty(namespaceUri))
                                {
                                    Logger.Information($"The namespace index of node '{nodeId.ToString()}' is invalid and the node format can not be updated.");
                                }
                                else
                                {
                                    unmonitoredEvent.IdAsExpandedNodeId = new ExpandedNodeId(nodeId.Identifier, nodeId.NamespaceIndex, namespaceUri, 0);
                                    currentNodeId = nodeId;
                                }
                            }

                            // if configured, get the key for the node, otherwise use the nodeId
                            Node node;
                            if (string.IsNullOrEmpty(unmonitoredEvent.Key))
                            {
                                if (FetchOpcNodeDisplayName == true)
                                {
                                    node = OpcUaClientSession.ReadNode(currentNodeId);
                                    unmonitoredEvent.Key = node.DisplayName.Text ?? currentNodeId.ToString();
                                }
                                else
                                {
                                    unmonitoredEvent.Key = currentNodeId.ToString();
                                }
                            }

                            // resolve all node and namespace references in the select and where clauses
                            EventFilter eventFilter = new EventFilter();
                            foreach (var selectClause in unmonitoredEvent.EventConfiguration.SelectClauses)
                            {
                                SimpleAttributeOperand simpleAttributeOperand = new SimpleAttributeOperand();
                                simpleAttributeOperand.AttributeId = selectClause.AttributeId.ResolveAttributeId();
                                simpleAttributeOperand.IndexRange  = selectClause.IndexRange;
                                NodeId typeId = selectClause.TypeId.ToNodeId(_namespaceTable);
                                simpleAttributeOperand.TypeDefinitionId = new NodeId(typeId);
                                QualifiedNameCollection browsePaths = new QualifiedNameCollection();
                                foreach (var browsePath in selectClause.BrowsePaths)
                                {
                                    browsePaths.Add(QualifiedName.Parse(browsePath));
                                }
                                simpleAttributeOperand.BrowsePath = browsePaths;
                                eventFilter.SelectClauses.Add(simpleAttributeOperand);
                            }
                            foreach (var whereClauseElement in unmonitoredEvent.EventConfiguration.WhereClause)
                            {
                                ContentFilterElement contentFilterElement = new ContentFilterElement();
                                contentFilterElement.FilterOperator = whereClauseElement.Operator.ResolveFilterOperator();
                                switch (contentFilterElement.FilterOperator)
                                {
                                case FilterOperator.OfType:
                                case FilterOperator.InView:
                                    if (whereClauseElement.Operands.Count != 1)
                                    {
                                        Logger.Error($"The where clause element '{whereClauseElement.ToString()}' must contain 1 operands.");
                                        continue;
                                    }
                                    FilterOperand[] filterOperands = new FilterOperand[1];
                                    TypeInfo        typeInfo       = new TypeInfo(BuiltInType.NodeId, ValueRanks.Scalar);
                                    filterOperands[0] = whereClauseElement.Operands[0].GetOperand(typeInfo);
                                    eventFilter.WhereClause.Push(contentFilterElement.FilterOperator, filterOperands);
                                    break;

                                case FilterOperator.Equals:
                                case FilterOperator.IsNull:
                                case FilterOperator.GreaterThan:
                                case FilterOperator.LessThan:
                                case FilterOperator.GreaterThanOrEqual:
                                case FilterOperator.LessThanOrEqual:
                                case FilterOperator.Like:
                                case FilterOperator.Not:
                                case FilterOperator.Between:
                                case FilterOperator.InList:
                                case FilterOperator.And:
                                case FilterOperator.Or:
                                case FilterOperator.Cast:
                                case FilterOperator.BitwiseAnd:
                                case FilterOperator.BitwiseOr:
                                case FilterOperator.RelatedTo:
                                default:
                                    Logger.Error($"The operator '{contentFilterElement.FilterOperator.ToString()}' is not supported.");
                                    break;
                                }
                            }

                            // add the new monitored event.
                            IOpcUaMonitoredItem monitoredItem = new OpcUaMonitoredItem()
                            {
                                StartNodeId      = currentNodeId,
                                AttributeId      = Attributes.EventNotifier,
                                DisplayName      = unmonitoredEvent.Key,
                                MonitoringMode   = unmonitoredEvent.MonitoringMode,
                                SamplingInterval = 0,
                                QueueSize        = unmonitoredEvent.QueueSize,
                                DiscardOldest    = unmonitoredEvent.DiscardOldest,
                                Filter           = eventFilter
                            };

                            monitoredItem.Notification += unmonitoredEvent.NotificationEventHandler;
                            opcEventSubscription.OpcUaClientSubscription.AddItem(monitoredItem);
                            unmonitoredEvent.OpcUaClientMonitoredItem = monitoredItem;
                            unmonitoredEvent.State       = OpcMonitoredItemState.Monitored;
                            unmonitoredEvent.EndpointUrl = EndpointUrl;
                            Logger.Verbose($"Created monitored event for node '{currentNodeId.ToString()}' in subscription with id '{opcEventSubscription.OpcUaClientSubscription.Id}' on endpoint '{EndpointUrl}' (version: {NodeConfigVersion:X8})");
                            if (unmonitoredEvent.RequestedSamplingInterval != monitoredItem.SamplingInterval)
                            {
                                Logger.Information($"Sampling interval: requested: {unmonitoredEvent.RequestedSamplingInterval}; revised: {monitoredItem.SamplingInterval}");
                                unmonitoredEvent.SamplingInterval = monitoredItem.SamplingInterval;
                            }
                            if (additionalMonitoredEventsCount % 10000 == 0)
                            {
                                Logger.Information($"Now monitoring {monitoredEventsCount + additionalMonitoredEventsCount} events in subscription with id '{opcEventSubscription.OpcUaClientSubscription.Id}'");
                            }
                        }
                        catch (Exception e) when(e.GetType() == typeof(ServiceResultException))
                        {
                            ServiceResultException sre = (ServiceResultException)e;

                            switch ((uint)sre.Result.StatusCode)
                            {
                            case StatusCodes.BadSessionIdInvalid:
                            {
                                Logger.Information($"Session with Id {OpcUaClientSession.SessionId} is no longer available on endpoint '{EndpointUrl}'. Cleaning up.");
                                // clean up the session
                                InternalDisconnect();
                                break;
                            }

                            case StatusCodes.BadNodeIdInvalid:
                            case StatusCodes.BadNodeIdUnknown:
                            {
                                Logger.Error($"Failed to monitor node '{currentNodeId}' on endpoint '{EndpointUrl}'.");
                                Logger.Error($"OPC UA ServiceResultException is '{sre.Result}'. Please check your publisher configuration for this node.");
                                break;
                            }

                            default:
                            {
                                Logger.Error($"Unhandled OPC UA ServiceResultException '{sre.Result}' when monitoring node '{currentNodeId}' on endpoint '{EndpointUrl}'. Continue.");
                                break;
                            }
                            }
                        }
                        catch (Exception e)
                        {
                            Logger.Error(e, $"Failed to monitor node '{currentNodeId}' on endpoint '{EndpointUrl}'");
                        }
                    }
                    opcEventSubscription.OpcUaClientSubscription.SetPublishingMode(true);
                    opcEventSubscription.OpcUaClientSubscription.ApplyChanges();
                    stopWatch.Stop();
                    if (haveUnmonitoredEvents == true)
                    {
                        monitoredEventsCount = opcEventSubscription.OpcMonitoredItems.Count(i => (i.State == OpcMonitoredItemState.Monitored));
                        Logger.Information($"Done processing unmonitored events on endpoint '{EndpointUrl}' took {stopWatch.ElapsedMilliseconds} msec. Now monitoring {monitoredEventsCount} events in subscription with id '{opcEventSubscription.OpcUaClientSubscription.Id}'.");
                    }
                }
            }
            catch (Exception e)
            {
                Logger.Error(e, "Exception");
            }
            finally
            {
                if (sessionLocked)
                {
                    ReleaseSession();
                }
            }
        }