/// <summary>
        /// Initialize a new OPC UA client connection
        /// </summary>
        /// <param name="clientName"></param>
        /// <param name="configPath"></param>
        /// <param name="opcUaUrl"></param>
        /// <param name="sessionName"></param>
        /// <param name="sessionTimeout"></param>
        /// <param name="keepAlive"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ServiceResultException"></exception>
        public async Task InitializeOpcUaClientConnection(string clientName,
                                                          string configPath,
                                                          string opcUaUrl,
                                                          string sessionName,
                                                          uint sessionTimeout,
                                                          KeepAliveEventHandler keepAlive = null)
        {
            this.ClientName  = string.IsNullOrWhiteSpace(clientName) ? throw new ArgumentNullException(nameof(clientName)) : clientName;
            this.ConfigPath  = string.IsNullOrWhiteSpace(configPath) ? throw new ArgumentNullException(nameof(configPath)) : configPath;
            this.OpcUaUrl    = string.IsNullOrWhiteSpace(opcUaUrl) ? throw new ArgumentNullException(nameof(opcUaUrl)) : opcUaUrl;
            this.SessionName = string.IsNullOrWhiteSpace(sessionName) ? throw new ArgumentNullException(nameof(sessionName)) : sessionName;
            if (sessionTimeout == 0)
            {
                throw new ArgumentException(nameof(sessionTimeout));
            }

            var clientApplicationConfig = await this.CreateOpcUaConfiguration(clientName : this.ClientName,
                                                                              configPath : this.ConfigPath);

            var selectedEndpoint = this.CreateOpcUaEndpoint(opcUrl: this.OpcUaUrl);

            await this.CreateOpcUaSession(applicationConfig : clientApplicationConfig,
                                          selectedEndpoint : selectedEndpoint,
                                          sessionName : this.SessionName,
                                          sessionTimeout : sessionTimeout,
                                          keepAlive : keepAlive);
        }
示例#2
0
        private async Task WhenKeepAliveStopped(CancellationToken token)
        {
            if (KeepAliveStopped)
            {
                return;
            }
            var tcs = new TaskCompletionSource <bool>();
            KeepAliveEventHandler handler = (s, e) =>
            {
                if (ServiceResult.IsBad(e.Status))
                {
                    tcs.TrySetResult(true);
                }
            };

            using (token.Register(state => ((TaskCompletionSource <bool>)state).TrySetCanceled(), tcs, false))
            {
                try
                {
                    KeepAlive += handler;
                    await tcs.Task;
                }
                finally
                {
                    KeepAlive -= handler;
                }
            }
        }
        /// <summary>
        /// Create OPC UA client session
        /// </summary>
        /// <param name="session"></param>
        /// <param name="keepAlive"></param>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ServiceResultException"></exception>
        public void CreateOpcUaSession(Session session,
                                       KeepAliveEventHandler keepAlive = null)
        {
            this.Session = session ?? throw new ArgumentNullException(nameof(session));

            this.RegisterKeepAlive(keepAlive: keepAlive);
        }
 /// <summary>
 /// Register the keep alive
 /// </summary>
 /// <param name="keepAlive"></param>
 private void RegisterKeepAlive(KeepAliveEventHandler keepAlive)
 {
     // register keep alive handler
     if (keepAlive == null)
     {
         this.Session.KeepAlive += this.SessionKeepAlive_Event;
     }
     // register what was passed in
     else
     {
         this.Session.KeepAlive += keepAlive;
     }
 }
        /// <summary>
        /// Create OPC UA client session
        /// </summary>
        /// <param name="applicationConfig"></param>
        /// <param name="selectedEndpoint"></param>
        /// <param name="sessionName"></param>
        /// <param name="sessionTimeout"></param>
        /// <param name="keepAlive"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ServiceResultException"></exception>
        public async Task CreateOpcUaSession(ApplicationConfiguration applicationConfig,
                                             EndpointDescription selectedEndpoint,
                                             string sessionName,
                                             uint sessionTimeout,
                                             KeepAliveEventHandler keepAlive = null)
        {
            if (applicationConfig == null)
            {
                throw new ArgumentNullException(nameof(applicationConfig));
            }
            if (selectedEndpoint == null)
            {
                throw new ArgumentNullException(nameof(selectedEndpoint));
            }
            if (string.IsNullOrWhiteSpace(sessionName))
            {
                throw new ArgumentNullException(nameof(sessionName));
            }
            this.SessionTimeout = sessionTimeout == 0 ? throw new ArgumentException(nameof(sessionTimeout)) : sessionTimeout;

            var endpointConfiguration = EndpointConfiguration.Create(applicationConfiguration: applicationConfig);

            var endpoint = new ConfiguredEndpoint(collection: null,
                                                  description: selectedEndpoint,
                                                  configuration: endpointConfiguration);

            this.Session = await Session.Create(configuration : applicationConfig,
                                                endpoint : endpoint,
                                                updateBeforeConnect : false,
                                                sessionName : sessionName,
                                                sessionTimeout : this.SessionTimeout,
                                                identity : this.User,
                                                preferredLocales : null);

            this.RegisterKeepAlive(keepAlive: keepAlive);
        }
示例#6
0
        /// <summary>
        /// Tests the session reconnect.
        /// </summary>
        private bool DoReconnectTest()
        {
            double increment = MaxProgress/6;
            double position  = 0;

            bool success = true;
            
            lock (m_messages)
            {
                m_messages.Clear();
            }

            int currentKeepAlive = Session.KeepAliveInterval;
            List<Subscription> subscriptions = new List<Subscription>();
            KeepAliveEventHandler keepAliveHandler = new KeepAliveEventHandler(Session_Reconnect);
            NotificationEventHandler notificationHandler = new NotificationEventHandler(Session_Notification);

            try
            {
                Session.KeepAlive += keepAliveHandler;
                Session.Notification += notificationHandler;

                for (int publishingInterval = 1000; publishingInterval <= 10000; publishingInterval += 1000)
                {
                    Subscription subscription = new Subscription();

                    subscription.MaxMessageCount = 100;
                    subscription.LifetimeCount = 100;
                    subscription.KeepAliveCount = 10;
                    subscription.PublishingEnabled = true;
                    subscription.PublishingInterval = publishingInterval;

                    MonitoredItem monitoredItem = new MonitoredItem();

                    monitoredItem.StartNodeId = VariableIds.Server_ServerStatus_CurrentTime;
                    monitoredItem.AttributeId = Attributes.Value;
                    monitoredItem.SamplingInterval = -1;
                    monitoredItem.QueueSize = 0;
                    monitoredItem.DiscardOldest = true;

                    subscription.AddItem(monitoredItem);
                    Session.AddSubscription(subscription);
                    subscription.Create();
                    subscriptions.Add(subscription);
                }

                m_keepAliveCount = 0;
                Session.KeepAliveInterval = 1000;
                Log("Setting keep alive interval to {0}ms.", Session.KeepAliveInterval);

                int testDuration = 3000;

                for (int ii = 0; ii < 6; ii++)
                {
                    Session.Reconnect();

                    Log("Session reconnected. KeepAlives={0}", m_keepAliveCount);

                    if (m_errorEvent.WaitOne(testDuration, false))
                    {
                        Log("Unexpected error waiting for session keep alives. {0}", m_error.ToLongString());
                        return false;
                    }

                    position += increment;
                    ReportProgress(position);
                }
            }
            finally
            {
                Session.RemoveSubscriptions(subscriptions);
                Session.KeepAliveInterval = currentKeepAlive;
                Session.KeepAlive -= keepAliveHandler;
                Session.Notification -= notificationHandler;
            } 
                
            ReportProgress(MaxProgress);

            lock (m_messages)
            {
                foreach (KeyValuePair<uint,List<uint>> entry in m_messages)
                {
                    entry.Value.Sort();

                    for (int ii = 0; ii < entry.Value.Count-1; ii++)
                    {
                        if (entry.Value[ii+1] - entry.Value[ii] > 1)
                        {
                            Log("Missing message. Subscription={0}, SequenceNumber={1}-{2}", entry.Key, entry.Value[ii]+1, entry.Value[ii+1]-1);
                        }

                        if (entry.Value[ii+1] == entry.Value[ii])
                        {
                            // Log("Duplicate message. Subscription={0}, SequenceNumber={1}", entry.Key, entry.Value[ii]);
                        }
                    }
                }
            }

            return success;
        }
示例#7
0
        /// <summary>
        /// Tests the session keep alive when there are no errors. 
        /// </summary>
        private bool DoKeepAliveTest()
        {
            bool success = true;
            
            double increment = MaxProgress/3;
            double position  = 0;

            m_keepAliveCount = 0;

            int currentKeepAlive = Session.KeepAliveInterval;
            List<Subscription> subscriptions = new List<Subscription>();
            KeepAliveEventHandler handler = new KeepAliveEventHandler(Session_KeepAlive); 

            try
            {
                Session.KeepAlive += handler;

                // add several subscriptions with long publish intervals.
                for (int publishingInterval = 10000; publishingInterval <= 20000; publishingInterval += 1000)
                {
                    Subscription subscription = new Subscription();

                    subscription.MaxMessageCount = 100;
                    subscription.LifetimeCount = 100;
                    subscription.KeepAliveCount = 10;
                    subscription.PublishingEnabled = true;
                    subscription.PublishingInterval = publishingInterval;

                    MonitoredItem monitoredItem = new MonitoredItem();

                    monitoredItem.StartNodeId = VariableIds.Server_ServerStatus_CurrentTime;
                    monitoredItem.AttributeId = Attributes.Value;
                    monitoredItem.SamplingInterval = -1;
                    monitoredItem.QueueSize = 0;
                    monitoredItem.DiscardOldest = true;

                    subscription.AddItem(monitoredItem);
                    Session.AddSubscription(subscription);
                    subscription.Create();
                    subscriptions.Add(subscription);
                }
                
                // get a value to read.
                ReadValueId nodeToRead = new ReadValueId();
                nodeToRead.NodeId = VariableIds.Server_ServerStatus;
                nodeToRead.AttributeId = Attributes.Value;
                ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
                nodesToRead.Add(nodeToRead);

                int testDuration = 5000;

                // make sure the keep alives come at the expected rate.
                for (int keepAliveInterval = 500; keepAliveInterval < 2000; keepAliveInterval += 500)
                {
                    m_keepAliveCount = 0;

                    DateTime start = DateTime.UtcNow;
                    
                    DataValueCollection results = null;
                    DiagnosticInfoCollection diagnosticsInfos = null;

                    Session.Read(
                        null,
                        0,
                        TimestampsToReturn.Neither,
                        nodesToRead,
                        out results,
                        out diagnosticsInfos);

                    ClientBase.ValidateResponse(results, nodesToRead);
                    ClientBase.ValidateDiagnosticInfos(diagnosticsInfos, nodesToRead);

                    ServerStatusDataType status = ExtensionObject.ToEncodeable(results[0].Value as ExtensionObject) as ServerStatusDataType;

                    if (status == null)
                    {
                        Log("Server did not return a valid ServerStatusDataType structure. Value={0}, Status={1}", results[0].WrappedValue, results[0].StatusCode);
                        return false;
                    }

                    if ((DateTime.UtcNow - start).TotalSeconds > 1)
                    {
                        Log("Unexpected delay reading the ServerStatus structure. Delay={0}s", (DateTime.UtcNow - start).TotalSeconds);
                        return false;
                    }

                    Log("Setting keep alive interval to {0}ms.", keepAliveInterval);

                    Session.KeepAliveInterval = keepAliveInterval;

                    if (m_errorEvent.WaitOne(testDuration, false))
                    {
                        Log("Unexpected error waiting for session keep alives. {0}", m_error.ToLongString());
                        return false;
                    }

                    if (m_keepAliveCount < testDuration / keepAliveInterval)
                    {
                        Log("Missing session keep alives. Expected={0}, Actual={1}", testDuration / keepAliveInterval, m_keepAliveCount);
                        return false;
                    }

                    Log("{0} keep alives received in {1}ms.", m_keepAliveCount, testDuration);

                    position += increment;
                    ReportProgress(position);
                }

                ReportProgress(MaxProgress);
            }
            finally
            {
                Session.RemoveSubscriptions(subscriptions);
                Session.KeepAliveInterval = currentKeepAlive;
                Session.KeepAlive -= handler;
            }

            return success;
        }
示例#8
0
        /// <summary>
        /// Tests the session reconnect.
        /// </summary>
        private bool DoReconnectTest()
        {
            double increment = MaxProgress / 6;
            double position  = 0;

            bool success = true;

            lock (m_messages)
            {
                m_messages.Clear();
            }

            int currentKeepAlive = Session.KeepAliveInterval;
            List <Subscription>      subscriptions       = new List <Subscription>();
            KeepAliveEventHandler    keepAliveHandler    = new KeepAliveEventHandler(Session_Reconnect);
            NotificationEventHandler notificationHandler = new NotificationEventHandler(Session_Notification);

            try
            {
                Session.KeepAlive    += keepAliveHandler;
                Session.Notification += notificationHandler;

                for (int publishingInterval = 1000; publishingInterval <= 10000; publishingInterval += 1000)
                {
                    Subscription subscription = new Subscription();

                    subscription.MaxMessageCount    = 100;
                    subscription.LifetimeCount      = 100;
                    subscription.KeepAliveCount     = 10;
                    subscription.PublishingEnabled  = true;
                    subscription.PublishingInterval = publishingInterval;

                    MonitoredItem monitoredItem = new MonitoredItem();

                    monitoredItem.StartNodeId      = VariableIds.Server_ServerStatus_CurrentTime;
                    monitoredItem.AttributeId      = Attributes.Value;
                    monitoredItem.SamplingInterval = -1;
                    monitoredItem.QueueSize        = 0;
                    monitoredItem.DiscardOldest    = true;

                    subscription.AddItem(monitoredItem);
                    Session.AddSubscription(subscription);
                    subscription.Create();
                    subscriptions.Add(subscription);
                }

                m_keepAliveCount          = 0;
                Session.KeepAliveInterval = 1000;
                Log("Setting keep alive interval to {0}ms.", Session.KeepAliveInterval);

                int testDuration = 3000;

                for (int ii = 0; ii < 6; ii++)
                {
                    Session.Reconnect();

                    Log("Session reconnected. KeepAlives={0}", m_keepAliveCount);

                    if (m_errorEvent.WaitOne(testDuration, false))
                    {
                        Log("Unexpected error waiting for session keep alives. {0}", m_error.ToLongString());
                        return(false);
                    }

                    position += increment;
                    ReportProgress(position);
                }
            }
            finally
            {
                Session.RemoveSubscriptions(subscriptions);
                Session.KeepAliveInterval = currentKeepAlive;
                Session.KeepAlive        -= keepAliveHandler;
                Session.Notification     -= notificationHandler;
            }

            ReportProgress(MaxProgress);

            lock (m_messages)
            {
                foreach (KeyValuePair <uint, List <uint> > entry in m_messages)
                {
                    entry.Value.Sort();

                    for (int ii = 0; ii < entry.Value.Count - 1; ii++)
                    {
                        if (entry.Value[ii + 1] - entry.Value[ii] > 1)
                        {
                            Log("Missing message. Subscription={0}, SequenceNumber={1}-{2}", entry.Key, entry.Value[ii] + 1, entry.Value[ii + 1] - 1);
                        }

                        if (entry.Value[ii + 1] == entry.Value[ii])
                        {
                            // Log("Duplicate message. Subscription={0}, SequenceNumber={1}", entry.Key, entry.Value[ii]);
                        }
                    }
                }
            }

            return(success);
        }
示例#9
0
        /// <summary>
        /// Tests the session keep alive when there are no errors.
        /// </summary>
        private bool DoKeepAliveTest()
        {
            bool success = true;

            double increment = MaxProgress / 3;
            double position  = 0;

            m_keepAliveCount = 0;

            int currentKeepAlive = Session.KeepAliveInterval;
            List <Subscription>   subscriptions = new List <Subscription>();
            KeepAliveEventHandler handler       = new KeepAliveEventHandler(Session_KeepAlive);

            try
            {
                Session.KeepAlive += handler;

                // add several subscriptions with long publish intervals.
                for (int publishingInterval = 10000; publishingInterval <= 20000; publishingInterval += 1000)
                {
                    Subscription subscription = new Subscription();

                    subscription.MaxMessageCount    = 100;
                    subscription.LifetimeCount      = 100;
                    subscription.KeepAliveCount     = 10;
                    subscription.PublishingEnabled  = true;
                    subscription.PublishingInterval = publishingInterval;

                    MonitoredItem monitoredItem = new MonitoredItem();

                    monitoredItem.StartNodeId      = VariableIds.Server_ServerStatus_CurrentTime;
                    monitoredItem.AttributeId      = Attributes.Value;
                    monitoredItem.SamplingInterval = -1;
                    monitoredItem.QueueSize        = 0;
                    monitoredItem.DiscardOldest    = true;

                    subscription.AddItem(monitoredItem);
                    Session.AddSubscription(subscription);
                    subscription.Create();
                    subscriptions.Add(subscription);
                }

                // get a value to read.
                ReadValueId nodeToRead = new ReadValueId();
                nodeToRead.NodeId      = VariableIds.Server_ServerStatus;
                nodeToRead.AttributeId = Attributes.Value;
                ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
                nodesToRead.Add(nodeToRead);

                int testDuration = 5000;

                // make sure the keep alives come at the expected rate.
                for (int keepAliveInterval = 500; keepAliveInterval < 2000; keepAliveInterval += 500)
                {
                    m_keepAliveCount = 0;

                    DateTime start = DateTime.UtcNow;

                    DataValueCollection      results          = null;
                    DiagnosticInfoCollection diagnosticsInfos = null;

                    Session.Read(
                        null,
                        0,
                        TimestampsToReturn.Neither,
                        nodesToRead,
                        out results,
                        out diagnosticsInfos);

                    ClientBase.ValidateResponse(results, nodesToRead);
                    ClientBase.ValidateDiagnosticInfos(diagnosticsInfos, nodesToRead);

                    ServerStatusDataType status = ExtensionObject.ToEncodeable(results[0].Value as ExtensionObject) as ServerStatusDataType;

                    if (status == null)
                    {
                        Log("Server did not return a valid ServerStatusDataType structure. Value={0}, Status={1}", results[0].WrappedValue, results[0].StatusCode);
                        return(false);
                    }

                    if ((DateTime.UtcNow - start).TotalSeconds > 1)
                    {
                        Log("Unexpected delay reading the ServerStatus structure. Delay={0}s", (DateTime.UtcNow - start).TotalSeconds);
                        return(false);
                    }

                    Log("Setting keep alive interval to {0}ms.", keepAliveInterval);

                    Session.KeepAliveInterval = keepAliveInterval;

                    if (m_errorEvent.WaitOne(testDuration, false))
                    {
                        Log("Unexpected error waiting for session keep alives. {0}", m_error.ToLongString());
                        return(false);
                    }

                    if (m_keepAliveCount < testDuration / keepAliveInterval)
                    {
                        Log("Missing session keep alives. Expected={0}, Actual={1}", testDuration / keepAliveInterval, m_keepAliveCount);
                        return(false);
                    }

                    Log("{0} keep alives received in {1}ms.", m_keepAliveCount, testDuration);

                    position += increment;
                    ReportProgress(position);
                }

                ReportProgress(MaxProgress);
            }
            finally
            {
                Session.RemoveSubscriptions(subscriptions);
                Session.KeepAliveInterval = currentKeepAlive;
                Session.KeepAlive        -= handler;
            }

            return(success);
        }