Ejemplo n.º 1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SubscriptionBase"/> class.
        /// </summary>
        /// <param name="application">The UaApplication.</param>
        public SubscriptionBase(UaApplication application)
        {
            this.application = application ?? throw new ArgumentNullException(nameof(application));
            this.application.Completion.ContinueWith(t => this.stateMachineCts?.Cancel());
            this.logger           = this.application.LoggerFactory?.CreateLogger(this.GetType());
            this.errors           = new ErrorsContainer <string>(p => this.ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(p)));
            this.progress         = new Progress <CommunicationState>(s => this.State = s);
            this.propertyChanged += this.OnPropertyChanged;
            this.whenSubscribed   = new TaskCompletionSource <bool>();
            this.whenUnsubscribed = new TaskCompletionSource <bool>();
            this.whenUnsubscribed.TrySetResult(true);

            // register the action to be run on the ui thread, if there is one.
            if (SynchronizationContext.Current != null)
            {
                this.actionBlock = new ActionBlock <PublishResponse>(pr => this.OnPublishResponse(pr), new ExecutionDataflowBlockOptions {
                    SingleProducerConstrained = true, TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
                });
            }
            else
            {
                this.actionBlock = new ActionBlock <PublishResponse>(pr => this.OnPublishResponse(pr), new ExecutionDataflowBlockOptions {
                    SingleProducerConstrained = true
                });
            }

            // read [Subscription] attribute.
            var typeInfo = this.GetType().GetTypeInfo();
            var sa       = typeInfo.GetCustomAttribute <SubscriptionAttribute>();

            if (sa != null)
            {
                this.endpointUrl        = sa.EndpointUrl;
                this.publishingInterval = sa.PublishingInterval;
                this.keepAliveCount     = sa.KeepAliveCount;
                this.lifetimeCount      = sa.LifetimeCount;
            }

            // read [MonitoredItem] attributes.
            foreach (var propertyInfo in typeInfo.DeclaredProperties)
            {
                var mia = propertyInfo.GetCustomAttribute <MonitoredItemAttribute>();
                if (mia == null || string.IsNullOrEmpty(mia.NodeId))
                {
                    continue;
                }

                MonitoringFilter filter = null;
                if (mia.AttributeId == AttributeIds.Value && (mia.DataChangeTrigger != DataChangeTrigger.StatusValue || mia.DeadbandType != DeadbandType.None))
                {
                    filter = new DataChangeFilter()
                    {
                        Trigger = mia.DataChangeTrigger, DeadbandType = (uint)mia.DeadbandType, DeadbandValue = mia.DeadbandValue
                    };
                }

                var propType = propertyInfo.PropertyType;
                if (propType == typeof(DataValue))
                {
                    this.monitoredItems.Add(new DataValueMonitoredItem(
                                                target: this,
                                                property: propertyInfo,
                                                nodeId: ExpandedNodeId.Parse(mia.NodeId),
                                                indexRange: mia.IndexRange,
                                                attributeId: mia.AttributeId,
                                                samplingInterval: mia.SamplingInterval,
                                                filter: filter,
                                                queueSize: mia.QueueSize,
                                                discardOldest: mia.DiscardOldest));
                    continue;
                }

                if (propType == typeof(BaseEvent) || propType.GetTypeInfo().IsSubclassOf(typeof(BaseEvent)))
                {
                    this.monitoredItems.Add(new EventMonitoredItem(
                                                target: this,
                                                property: propertyInfo,
                                                nodeId: ExpandedNodeId.Parse(mia.NodeId),
                                                indexRange: mia.IndexRange,
                                                attributeId: mia.AttributeId,
                                                samplingInterval: mia.SamplingInterval,
                                                filter: new EventFilter()
                    {
                        SelectClauses = EventHelper.GetSelectClauses(propType)
                    },
                                                queueSize: mia.QueueSize,
                                                discardOldest: mia.DiscardOldest));
                    continue;
                }

                if (propType == typeof(ObservableQueue <DataValue>))
                {
                    this.monitoredItems.Add(new DataValueQueueMonitoredItem(
                                                target: this,
                                                property: propertyInfo,
                                                nodeId: ExpandedNodeId.Parse(mia.NodeId),
                                                indexRange: mia.IndexRange,
                                                attributeId: mia.AttributeId,
                                                samplingInterval: mia.SamplingInterval,
                                                filter: filter,
                                                queueSize: mia.QueueSize,
                                                discardOldest: mia.DiscardOldest));
                    continue;
                }

                if (propType.IsConstructedGenericType && propType.GetGenericTypeDefinition() == typeof(ObservableQueue <>))
                {
                    var elemType = propType.GenericTypeArguments[0];
                    if (elemType == typeof(BaseEvent) || elemType.GetTypeInfo().IsSubclassOf(typeof(BaseEvent)))
                    {
                        this.monitoredItems.Add((MonitoredItemBase)Activator.CreateInstance(
                                                    typeof(EventQueueMonitoredItem <>).MakeGenericType(elemType),
                                                    this,
                                                    propertyInfo,
                                                    ExpandedNodeId.Parse(mia.NodeId),
                                                    mia.AttributeId,
                                                    mia.IndexRange,
                                                    MonitoringMode.Reporting,
                                                    mia.SamplingInterval,
                                                    new EventFilter()
                        {
                            SelectClauses = EventHelper.GetSelectClauses(elemType)
                        },
                                                    mia.QueueSize,
                                                    mia.DiscardOldest));
                        continue;
                    }
                }

                this.monitoredItems.Add(new ValueMonitoredItem(
                                            target: this,
                                            property: propertyInfo,
                                            nodeId: ExpandedNodeId.Parse(mia.NodeId),
                                            indexRange: mia.IndexRange,
                                            attributeId: mia.AttributeId,
                                            samplingInterval: mia.SamplingInterval,
                                            filter: filter,
                                            queueSize: mia.QueueSize,
                                            discardOldest: mia.DiscardOldest));
            }

            this.stateMachineCts  = new CancellationTokenSource();
            this.stateMachineTask = Task.Run(() => this.StateMachineAsync(this.stateMachineCts.Token));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// The state machine manages the state of the subscription.
        /// </summary>
        /// <param name="token">A cancellation token.</param>
        /// <returns>A task.</returns>
        private async Task StateMachineAsync(CancellationToken token = default)
        {
            while (!token.IsCancellationRequested)
            {
                await this.whenSubscribed.Task;

                this.progress.Report(CommunicationState.Opening);

                try
                {
                    // get a channel.
                    this.innerChannel = await this.application.GetChannelAsync(this.endpointUrl, token);

                    try
                    {
                        // create the subscription.
                        var subscriptionRequest = new CreateSubscriptionRequest
                        {
                            RequestedPublishingInterval = this.publishingInterval,
                            RequestedMaxKeepAliveCount  = this.keepAliveCount,
                            RequestedLifetimeCount      = Math.Max(this.lifetimeCount, 3 * this.keepAliveCount),
                            PublishingEnabled           = true
                        };
                        var subscriptionResponse = await this.innerChannel.CreateSubscriptionAsync(subscriptionRequest).ConfigureAwait(false);

                        // link up the dataflow blocks
                        var id        = this.subscriptionId = subscriptionResponse.SubscriptionId;
                        var linkToken = this.innerChannel.LinkTo(this.actionBlock, pr => pr.SubscriptionId == id);

                        try
                        {
                            // create the monitored items.
                            var items = this.monitoredItems.ToList();
                            if (items.Count > 0)
                            {
                                var requests = items.Select(m => new MonitoredItemCreateRequest {
                                    ItemToMonitor = new ReadValueId {
                                        NodeId = ExpandedNodeId.ToNodeId(m.NodeId, this.InnerChannel.NamespaceUris), AttributeId = m.AttributeId, IndexRange = m.IndexRange
                                    }, MonitoringMode = m.MonitoringMode, RequestedParameters = new MonitoringParameters {
                                        ClientHandle = m.ClientId, DiscardOldest = m.DiscardOldest, QueueSize = m.QueueSize, SamplingInterval = m.SamplingInterval, Filter = m.Filter
                                    }
                                }).ToArray();
                                var itemsRequest = new CreateMonitoredItemsRequest
                                {
                                    SubscriptionId = id,
                                    ItemsToCreate  = requests,
                                };
                                var itemsResponse = await this.innerChannel.CreateMonitoredItemsAsync(itemsRequest);

                                for (int i = 0; i < itemsResponse.Results.Length; i++)
                                {
                                    var item   = items[i];
                                    var result = itemsResponse.Results[i];
                                    item.OnCreateResult(result);
                                    if (StatusCode.IsBad(result.StatusCode))
                                    {
                                        this.logger?.LogError($"Error creating MonitoredItem for {item.NodeId}. {StatusCodes.GetDefaultMessage(result.StatusCode)}");
                                    }
                                }
                            }

                            this.progress.Report(CommunicationState.Opened);

                            // wait here until channel is closing, unsubscribed or token cancelled.
                            try
                            {
                                await Task.WhenAny(
                                    this.WhenChannelClosingAsync(this.innerChannel, token),
                                    this.whenUnsubscribed.Task);
                            }
                            catch
                            {
                            }
                            finally
                            {
                                this.progress.Report(CommunicationState.Closing);
                            }
                        }
                        catch (Exception ex)
                        {
                            this.logger?.LogError($"Error creating MonitoredItems. {ex.Message}");
                            this.progress.Report(CommunicationState.Faulted);
                        }
                        finally
                        {
                            linkToken.Dispose();
                        }

                        if (this.innerChannel.State == CommunicationState.Opened)
                        {
                            try
                            {
                                // delete the subscription.
                                var deleteRequest = new DeleteSubscriptionsRequest
                                {
                                    SubscriptionIds = new uint[] { id }
                                };
                                await this.innerChannel.DeleteSubscriptionsAsync(deleteRequest);
                            }
                            catch (Exception ex)
                            {
                                this.logger?.LogError($"Error deleting subscription. {ex.Message}");
                                await Task.Delay(2000);
                            }
                        }

                        this.progress.Report(CommunicationState.Closed);
                    }
                    catch (Exception ex)
                    {
                        this.logger?.LogError($"Error creating subscription. {ex.Message}");
                        this.progress.Report(CommunicationState.Faulted);
                        await Task.Delay(2000);
                    }
                }
                catch (Exception ex)
                {
                    this.logger?.LogTrace($"Error getting channel. {ex.Message}");
                    this.progress.Report(CommunicationState.Faulted);
                    await Task.Delay(2000);
                }
            }
        }
Ejemplo n.º 3
0
 public Variant(ExpandedNodeId value)
 {
     this.Value           = value;
     this.Type            = VariantType.ExpandedNodeId;
     this.ArrayDimensions = null;
 }
Ejemplo n.º 4
0
 public XmlEncodingIdAttribute(string s)
 {
     this.NodeId = ExpandedNodeId.Parse(s);
 }
 public DataTypeIdAttribute(string s)
 {
     this.NodeId = ExpandedNodeId.Parse(s);
 }