Esempio n. 1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="UaApplication"/> class.
        /// </summary>
        /// <param name="localDescription">The <see cref="ApplicationDescription"/> of the local application.</param>
        /// <param name="certificateStore">The local certificate store.</param>
        /// <param name="identityProvider">An asynchronous function that provides the user identity. Provide an <see cref="AnonymousIdentity"/>, <see cref="UserNameIdentity"/>, <see cref="IssuedIdentity"/> or <see cref="X509Identity"/>.</param>
        /// <param name="mappedEndpoints">The mapped endpoints.</param>
        /// <param name="loggerFactory">The logger factory.</param>
        /// <param name="options">The application options.</param>
        /// <param name="additionalTypes">Any additional types to be registered with encoder.</param>
        public UaApplication(
            ApplicationDescription localDescription,
            ICertificateStore certificateStore,
            Func <EndpointDescription, Task <IUserIdentity> > identityProvider,
            IEnumerable <MappedEndpoint> mappedEndpoints,
            ILoggerFactory loggerFactory       = null,
            UaApplicationOptions options       = null,
            IEnumerable <Type> additionalTypes = null)
        {
            if (localDescription == null)
            {
                throw new ArgumentNullException(nameof(localDescription));
            }

            this.LocalDescription     = localDescription;
            this.CertificateStore     = certificateStore;
            this.UserIdentityProvider = identityProvider;
            this.MappedEndpoints      = mappedEndpoints;
            this.LoggerFactory        = loggerFactory;
            this.Options         = options ?? new UaApplicationOptions();
            this.AdditionalTypes = additionalTypes;

            this.logger     = loggerFactory?.CreateLogger <UaApplication>();
            this.channelMap = new ConcurrentDictionary <string, Lazy <Task <UaTcpSessionChannel> > >();

            lock (globalLock)
            {
                if (appInstance != null)
                {
                    throw new InvalidOperationException("You can only create a single instance of this type.");
                }

                appInstance = this;
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Closes the communication channels to the remote endpoint.
        /// </summary>
        /// <param name="disposing">If true, then dispose managed resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing & !this.disposed)
            {
                this.disposed = true;
                this.completionTask.TrySetResult(true);

                lock (globalLock)
                {
                    appInstance = null;
                }

                foreach (var value in this.channelMap.Values)
                {
                    var task = value.Value;
                    if (task.Status == TaskStatus.RanToCompletion)
                    {
                        try
                        {
                            task.Result.CloseAsync().Wait(2000);
                        }
                        catch { }
                    }
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SubscriptionBase"/> class.
        /// </summary>
        public SubscriptionBase()
        {
            this.application = UaApplication.Current;
            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: NodeId.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: NodeId.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: NodeId.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,
                                                    NodeId.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: NodeId.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));
        }