OPCFoundation.NetStandard.Opc.Ua是OPC基金会发布的开源OPC UA包,提供Client读写库方便读写OPC 服务器数据。

     OPCFoundation.NetStandard.Opc.Ua开源项目地址:https://github.com/OPCFoundation/UA-.NETStandard

     使用时有几点需要注意。

1、订阅分组

        OPC UA的数据订阅分组,和OPC DA的有所不同,每个组数据项有限,这个值具体是多少与服务器的配置有关,一般几百到上千。每个组的订阅名称也不能相同,需要考虑订阅名称分类。服务器对与订阅资源是有限的,有的服务器必须显式的释放订阅资源,不然会造成订阅资源耗尽而订阅失败,必须重启服务端软件才能解决。 

2、连接断开

     OPC Client与服务器连接断开有两种情况:主动断开和被动断开

     客户端主动断开时,必须先注销订阅的数据分组项,再进行断开。目前这个库不能在连接关闭时自动释放所有服务器的连接资源,这个也是这个库不太友好的地方。
     如果是服务端主动断开,很可能是服务器关闭了,这时直接关闭即可。

3、数据读取

      数据读取有订阅、同步和异步几种方法。订阅较为复杂但性能高、占用的网络带宽也最少。同步与异步仅调用语法有差异,其他类似。

      同步或异步都数据时,读多少数据点,就传入多少,然后到返回值中拿数据,C#可以作比较好的类型转换。

4、数据写入

      OPC UA在数据写入时,对数据类型有严格要求,数据类型不会自动转换,会写入失败。如果仅在C#系统内部写入数据,且仅少数点写入这时读有次数据,记录返回的数据类型,固定编码写入。

     在数据量较多,且有数据订阅的情况下,也可以记录每个点的数据类型,在写入数据时索引数据类型,然后自动转换。

    在把数据接口封装为API的情况下,同一个数据可以解析为很多数据类型,比如数据123,可以是Byte,I2、U2、I4、U4、R4等很多类型,反序列化时一般会解析为Single,直接调用写入会因数据类型不正确而失败。这时除了使用索引,自己处理数据兼容性问题,也可以多写几个wrapper来处理数据类型转换问题。

   示例的Controller类代码如下:

    [ApiController]
    [Route("[controller]/[action]")]
    public class OpcUaControlServiceController : ControllerBase
    {
        private readonly ILogger<OpcUaControlServiceController> _logger;

                                                                                               
        public OpcUaControlServiceController(ILogger<OpcUaControlServiceController> logger)
        {
            _logger = logger;
        }
        /// <summary>
        /// 获取服务运行信息
        /// </summary>
        /// <returns>运行信息概览JSON</returns>
        [HttpPost,HttpGet]
        public string info()
        {
            return ApiContentResultMsg.Success(OpcUaControlService.Instance.Info());
        }
        /// <summary>
        /// 启动OpcUa 控制服务
        /// </summary>
        /// <returns>执行信息JSON</returns>
        [HttpPost]
        public string Start()
        {
            OpcUaControlService.Instance.Start();
            return ApiContentResultMsg.Success();
        }

        /// <summary>
        /// 停止OpcUa 控制服务
        /// </summary>
        /// <returns>执行信息JSON</returns>
        [HttpPost]
        public string ShutDown()
        {
            OpcUaControlService.Instance.ShutDown();
            return ApiContentResultMsg.Success();
        }

        /// <summary>
        /// 写入Int32 类型 OpcUa NodeId数据
        /// </summary>
        /// <returns>执行信息JSON</returns>
        [HttpPost]
        public string SyncWriteOpcUaInt32(String nodeId, Int32 value)
        {
            bool b = OpcUaControlService.Instance.SyncWriteOpcUaInt32(nodeId, value);
            return b?ApiContentResultMsg.Success(): ApiContentResultMsg.Error("write fail!");
       }

        /// <summary>
        /// 写入float 类型 OpcUa NodeId数据
        /// </summary>
        /// <returns>执行信息JSON</returns>
        [HttpPost]
        public string SyncWriteOpcUaFloat(String nodeId, float value)
        {
            bool b = OpcUaControlService.Instance.SyncWriteOpcUaFloat(nodeId, value);
            return b ? ApiContentResultMsg.Success() : ApiContentResultMsg.Error("write fail!");
        }

        /// <summary>
        /// 写入bool 类型 OpcUa NodeId数据
        /// </summary>
        /// <returns>执行信息JSON</returns>
        [HttpPost]
        public string SyncWriteOpcUaBool(String nodeId, bool value)
        {
            bool b = OpcUaControlService.Instance.SyncWriteOpcUaBool(nodeId, value);
            return b ? ApiContentResultMsg.Success() : ApiContentResultMsg.Error("write fail!");
        }

        /// <summary>
        /// 写入String 类型 OpcUa NodeId数据
        /// </summary>
        /// <returns>执行信息JSON</returns>
        [HttpPost]
        public string SyncWriteOpcUaString(String nodeId, String value)
        {
            bool b = OpcUaControlService.Instance.SyncWriteOpcUaString(nodeId, value);
            return b ? ApiContentResultMsg.Success() : ApiContentResultMsg.Error("write fail!");
        }

    }

5、参考资料

日本DeviceXPlorer OPC Server软件,在日系PLC和数控支持上比较友好,适用于1万点以内的采集服务,其自带了有个客户端的Demo,参考如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Opc.Ua.Client;
using Opc.Ua.Configuration;
using Opc.Ua;
using System.Security.Cryptography.X509Certificates;

namespace DxpUaSimpleAPI
{
    public class DxpUaSimpleClass
    {
        public struct ReadItemResults
        {
            public object m_readResultValue;
            public StatusCode m_resultCodes;
            public DateTime m_sourceTimeStamp;
            public DateTime m_serverTimeStamp;
        }
        public struct WriteItemResults
        {
            public StatusCode m_resultCodes;
        }

        public delegate void onAsyncReadCompleteDelegate(List<string> asyncReadNodeName, List<ReadItemResults> AsyncReadItemResults);
        public delegate void onAsyncWriteCompleteDelegate(List<string> asyncWriteNodeName, List<WriteItemResults> asyncResultStatus);
        public delegate void monitoredItemNotification(List<string> monitoredItems, List<object> monitoredItemValue);

        private Session m_clientSession = null;
        private Dictionary<string, Subscription> m_subscriptionMap = new Dictionary<string, Subscription>();
        private ApplicationInstance m_application = new ApplicationInstance();
        private List<Subscription> m_subscriptions = new List<Subscription>();
        public onAsyncReadCompleteDelegate m_ReadEventHandler = null;
        public onAsyncWriteCompleteDelegate m_WriteEventHandler = null;
        public monitoredItemNotification m_MonitoredEventHandler = null;

        public struct CertificateStore
        {
            public string m_applicationCertificateFileName;
            public string m_applicationCertificateStore;
            public string m_trustedIssuerCertificatesStore;
            public string m_TrustedPeerCertificatesStore;
            public string m_RejectedCertificateStore;
        }

        public struct BrowseNodeResults
        {
            public QualifiedName m_browseName;
            public ExpandedNodeId m_nodeIdList;
            public LocalizedText m_displayName;
            public StatusCode m_statusCodes;
        }

        public void Initialize()
        {
            m_application.ApplicationType = ApplicationType.Client;
            m_application.ConfigSectionName = "Opc.Ua.SampleClient";

            try
            {
                m_application.LoadApplicationConfiguration(false);
                m_application.CheckApplicationInstanceCertificate(false, 0);
            }
            catch (Exception ex)
            {
                Console.WriteLine(" Initialize Exception" + ex.Message);
            }
        }

        public bool Initialize(string sApplicationName, string sApplicationUri, string sProductUri, CertificateStore newCertificateStore, string sStoreType)
        {
            try
            {
                m_application.ApplicationConfiguration = new ApplicationConfiguration();
                if (sApplicationName == "")
                {
                    m_application.ApplicationConfiguration.ApplicationName = "OPC UA User Client";
                }
                if (sApplicationUri == "")
                {
                    m_application.ApplicationConfiguration.ApplicationUri = "urn:localhost:TAKEBISHI:UserClient";
                }
                if (sProductUri == "")
                {
                    m_application.ApplicationConfiguration.ProductUri = "http://opcfoundation.org/UA/SampleClient";
                }
                m_application.ApplicationConfiguration.ApplicationType = ApplicationType.Client;

                m_application.ApplicationConfiguration.SecurityConfiguration.ApplicationCertificate = new CertificateIdentifier(new X509Certificate2(newCertificateStore.m_applicationCertificateFileName));
                m_application.ApplicationConfiguration.SecurityConfiguration.ApplicationCertificate.StoreType = CertificateStoreType.Directory;
                m_application.ApplicationConfiguration.SecurityConfiguration.ApplicationCertificate.StorePath = newCertificateStore.m_applicationCertificateStore;
                m_application.ApplicationConfiguration.SecurityConfiguration.ApplicationCertificate.OpenStore();

               m_application.ApplicationConfiguration.SecurityConfiguration.TrustedIssuerCertificates.StoreType = sStoreType;
                m_application.ApplicationConfiguration.SecurityConfiguration.TrustedIssuerCertificates.StorePath = newCertificateStore.m_trustedIssuerCertificatesStore;
                m_application.ApplicationConfiguration.SecurityConfiguration.TrustedIssuerCertificates.OpenStore();

                m_application.ApplicationConfiguration.SecurityConfiguration.TrustedPeerCertificates.StoreType = sStoreType;
                m_application.ApplicationConfiguration.SecurityConfiguration.TrustedPeerCertificates.StorePath = newCertificateStore.m_TrustedPeerCertificatesStore;
                m_application.ApplicationConfiguration.SecurityConfiguration.TrustedPeerCertificates.OpenStore();

                m_application.ApplicationConfiguration.SecurityConfiguration.RejectedCertificateStore = new CertificateStoreIdentifier();
                m_application.ApplicationConfiguration.SecurityConfiguration.RejectedCertificateStore.StoreType = sStoreType;
                m_application.ApplicationConfiguration.SecurityConfiguration.RejectedCertificateStore.StorePath = newCertificateStore.m_RejectedCertificateStore;
                m_application.ApplicationConfiguration.SecurityConfiguration.RejectedCertificateStore.OpenStore();

                m_application.ApplicationConfiguration.SecurityConfiguration.AutoAcceptUntrustedCertificates = false;

                m_application.ApplicationConfiguration.CertificateValidator = new CertificateValidator();

                StringCollection wellKnownDiscoveryUrls = new StringCollection();
                wellKnownDiscoveryUrls.Add("http://{0}:52601/UADiscovery");
                wellKnownDiscoveryUrls.Add("opc.tcp://{0}:4840");
                wellKnownDiscoveryUrls.Add("http://{0}/UADiscovery/Default.svc");

                m_application.ApplicationConfiguration.ClientConfiguration = new ClientConfiguration();
                m_application.ApplicationConfiguration.ClientConfiguration.WellKnownDiscoveryUrls = wellKnownDiscoveryUrls;

                m_application.CheckApplicationInstanceCertificate(false, 0);
            }
            catch (Exception ex)
            {
                Console.WriteLine(" Initialize Exception" + ex.Message);
                return false;
            }
            return true;
        }

        public ConfiguredEndpoint GetEndPoint(string sUrl, MessageSecurityMode securityMode, string sSecurityPoricies)
        {
            try
            {

                ApplicationConfiguration configuration = m_application.ApplicationConfiguration;
                EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(configuration);
                EndpointDescription endpointDescription = null;
                endpointDescription = new EndpointDescription();

                endpointDescription.EndpointUrl = sUrl;
                endpointDescription.SecurityLevel = 0;
                endpointDescription.SecurityMode = securityMode;
                endpointDescription.SecurityPolicyUri = sSecurityPoricies;
                endpointDescription.Server.ApplicationName = endpointDescription.EndpointUrl;
                endpointDescription.Server.ApplicationType = ApplicationType.Server;
                endpointDescription.Server.ApplicationUri = endpointDescription.EndpointUrl;

                ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration);

                return endpoint;
            }
            catch (Exception ex)
            {
                Console.WriteLine(" GetEndPoint Exception" + ex.Message);
                return null;
            }
        }

        public bool Connect(string sUrl, MessageSecurityMode securityMode, string sSecurityPoricies)
        {
            ApplicationConfiguration configuration = m_application.ApplicationConfiguration;
            bool UpdateBeforeConnect = true;
            string sSessionName = "session1";
            uint nSessionTimeout = 3000;
            UserIdentity userIdentity = null;
            IList<string> PreferredLocales = null;

            ConfiguredEndpoint endpoint = GetEndPoint(sUrl, securityMode, sSecurityPoricies);

            try
            {
                m_clientSession = Session.Create(configuration, endpoint, UpdateBeforeConnect, sSessionName, nSessionTimeout, userIdentity, PreferredLocales);

                if (m_clientSession == null)
                {
                    return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(" Session Create Exception" + ex.Message);
                return false;
            }
        }

        public bool DisConnect()
        {
            if (m_subscriptions.Count() > 0)
            {
                for (int i = 0; i < m_subscriptions.Count(); i++)
                {
                    Subscription subscription = m_subscriptions[i];
                    if (m_subscriptionMap.ContainsKey(subscription.DisplayName))
                    {
                        subscription = m_subscriptionMap[subscription.DisplayName];
                        if (!RemoveAllMonitoredItems(subscription.DisplayName))
                        {
                            return false;
                        }
                    }
                }
                if (!m_clientSession.RemoveSubscriptions(m_subscriptions))
                {
                    return false;
                }
            }

            try
            {
                if (m_clientSession != null)
                {   
                    m_clientSession.Close();
                    m_clientSession.Dispose();
                    m_clientSession = null;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(" Session close Exception" + ex.Message);
                return false;
            }
            return true;
        }

        public bool BrowseNode(NodeId targetNodeId, NodeId ReferenceType, out List<BrowseNodeResults> results)
        {
            BrowseDescription nodeToBrowse = new BrowseDescription();
            BrowseDescriptionCollection nodesToBrowse = new BrowseDescriptionCollection();
            RequestHeader BrowseRequestHeader = new RequestHeader();
            ViewDescription BrowseView = new ViewDescription();
            BrowseResultCollection BrowseResults = new BrowseResultCollection();
            uint requestMaxReferencesPerNode = 0;
            DiagnosticInfoCollection BrowseDiagnosticsInfos = new DiagnosticInfoCollection();
            nodeToBrowse.ReferenceTypeId = ReferenceType;
            nodeToBrowse.NodeId = targetNodeId;
            nodeToBrowse.IncludeSubtypes = true;
            nodeToBrowse.NodeClassMask = (uint)(NodeClass.Object | NodeClass.Variable);
            nodeToBrowse.ResultMask = (uint)BrowseResultMask.All;
            nodeToBrowse.BrowseDirection = BrowseDirection.Forward;
            nodesToBrowse.Add(nodeToBrowse);
            results = new List<BrowseNodeResults>();
            BrowseNodeResults browseNodeResults = new BrowseNodeResults();
            browseNodeResults.m_browseName = null;
            browseNodeResults.m_nodeIdList = null;
            browseNodeResults.m_displayName = null;
            browseNodeResults.m_statusCodes = new StatusCode();
            try
            {
                m_clientSession.Browse(BrowseRequestHeader, BrowseView, requestMaxReferencesPerNode, nodesToBrowse, out BrowseResults, out BrowseDiagnosticsInfos);

                browseNodeResults.m_statusCodes = BrowseResults[0].StatusCode;
                for (int i = 0; i < BrowseResults[0].References.Count(); i++)
                {
                    browseNodeResults.m_browseName = BrowseResults[0].References[i].BrowseName;
                    browseNodeResults.m_nodeIdList = BrowseResults[0].References[i].NodeId;
                    browseNodeResults.m_displayName = BrowseResults[0].References[i].DisplayName;
                    results.Add(browseNodeResults);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(" BrowseNode Exception" + ex.Message);
                return false;
            }
            return true;
        }

        public bool SyncRead(List<NodeId> readItemList, out List<ReadItemResults> results)
        {
            RequestHeader ReadRequestHeader = new RequestHeader();
            ReadRequestHeader.ReturnDiagnostics = 5000;
            ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
            DataValueCollection ReadResults = new DataValueCollection();
            DiagnosticInfoCollection ReadDiagnosticsInfos = null;
            results = new List<ReadItemResults>();
            ReadItemResults readItemResults = new ReadItemResults();
            readItemResults.m_readResultValue = 0;
            readItemResults.m_resultCodes = new StatusCode();
            readItemResults.m_serverTimeStamp = new DateTime();
            readItemResults.m_sourceTimeStamp = new DateTime();

            try
            {
                foreach (NodeId nodeId in readItemList)
                {
                    ReadValueId readId = new ReadValueId();
                    readId.NodeId = nodeId;
                    readId.AttributeId = (uint)Attributes.Value;
                    nodesToRead.Add(readId);
                }

                m_clientSession.Read(ReadRequestHeader, 0, TimestampsToReturn.Both, nodesToRead, out ReadResults, out ReadDiagnosticsInfos);

                for (int i = 0; i < ReadResults.Count(); i++)
                {
                    readItemResults.m_resultCodes = ReadResults[i].StatusCode;
                    if (!StatusCode.IsBad(ReadResults[i].StatusCode))
                    {
                        readItemResults.m_readResultValue = ReadResults[i].Value;
                        readItemResults.m_sourceTimeStamp = ReadResults[i].SourceTimestamp;
                        readItemResults.m_serverTimeStamp = ReadResults[i].ServerTimestamp;
                    }
                    else
                    {
                        readItemResults.m_readResultValue = null;
                        readItemResults.m_sourceTimeStamp = DateTime.MinValue;
                        readItemResults.m_serverTimeStamp = DateTime.MinValue;
                    }
                    results.Add(readItemResults);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(" SyncRead Exception" + ex.Message);
                return false;
            }
            return true;
        }

        public bool SyncWrite(List<NodeId> writeNodeIdList, List<object> writeValueList, out List<WriteItemResults> Results)
        {
            RequestHeader WriteRequestHeader = null;
            Results = new List<WriteItemResults>();
            WriteItemResults writeItemResults = new WriteItemResults();
            writeItemResults.m_resultCodes = new StatusCode();
            WriteValueCollection writeValueCollection = new WriteValueCollection();
            StatusCodeCollection WriteResults = null;
            DiagnosticInfoCollection WriteDiagnosticsInfos = null;

            try
            {
                for (int i = 0; i < writeNodeIdList.Count(); i++)
                {
                    WriteValue valueToWrite = new WriteValue();
                    valueToWrite.NodeId = writeNodeIdList[i];
                    valueToWrite.AttributeId = (uint)Attributes.Value;
                    valueToWrite.Value.Value = writeValueList[i];
                    valueToWrite.Value.StatusCode = StatusCodes.Good;
                    valueToWrite.Value.ServerTimestamp = DateTime.MinValue;
                    writeValueCollection.Add(valueToWrite);
                }
                m_clientSession.Write(WriteRequestHeader, writeValueCollection, out WriteResults, out WriteDiagnosticsInfos);

                if (WriteResults.Count() > 0)
                {
                    for (int m = 0; m < WriteResults.Count(); m++)
                    {
                        writeItemResults.m_resultCodes = WriteResults[0];
                        Results.Add(writeItemResults);
                    }
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(" SyncWrite Exception" + ex.Message);
                return false;
            }
            return true;
        }

        public void ASyncRead(List<NodeId> readItemList)
        {
            ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
            try
            {
                foreach (NodeId nodeId in readItemList)
                {
                    ReadValueId readId = new ReadValueId();
                    readId.NodeId = nodeId;
                    readId.AttributeId = (uint)Attributes.Value;
                    nodesToRead.Add(readId);
                }

                m_clientSession.BeginRead(null, 0, TimestampsToReturn.Both, nodesToRead, new AsyncCallback(AsyncReadCompleted), nodesToRead);

            }
            catch (Exception ex)
            {
                Console.WriteLine(" ASyncRead Exception" + ex.Message);
            }
        }

        public void AsyncReadCompleted(IAsyncResult result)
        {
            try
            {
                if (!result.IsCompleted)
                {
                    return;
                }

                EndRead(result);

            }
            catch (Exception ex)
            {
                Console.WriteLine(" ASyncRead Exception" + ex.Message);
            }
        }

        public ResponseHeader EndRead(IAsyncResult result)
        {
            ReadResponse response = null;
            DataValueCollection results = new DataValueCollection();
            DiagnosticInfoCollection diagnosticInfos = new DiagnosticInfoCollection();
            ReadValueIdCollection nodesToRead = (ReadValueIdCollection)result.AsyncState;
            List<ReadItemResults> readResults = new List<ReadItemResults>();

            IServiceResponse genericResponse = m_clientSession.TransportChannel.EndSendRequest(result);

            if (genericResponse == null)
            {   
                throw new ServiceResultException(StatusCodes.BadUnknownResponse);
            }

            ValidateResponse(genericResponse.ResponseHeader);
            response = (ReadResponse)genericResponse;

            results = response.Results;
            diagnosticInfos = response.DiagnosticInfos;

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

            ReadItemResults readItemResults = new ReadItemResults();
            readItemResults.m_readResultValue = 0;
            readItemResults.m_resultCodes = new StatusCode();
            readItemResults.m_serverTimeStamp = new DateTime();
            readItemResults.m_sourceTimeStamp = new DateTime();

            List<string> asyncReadNodeName = new List<string>();

            for (int i = 0; i < results.Count; i++)
            {
                asyncReadNodeName.Add(nodesToRead[i].NodeId.ToString());
                readItemResults.m_resultCodes = results[i].StatusCode;
                if (!StatusCode.IsBad(results[i].StatusCode))
                {
                    readItemResults.m_readResultValue = results[i].Value;
                    readItemResults.m_sourceTimeStamp = results[i].SourceTimestamp;
                    readItemResults.m_serverTimeStamp = results[i].ServerTimestamp;
                }
                else
                {
                    readItemResults.m_readResultValue = null;
                    readItemResults.m_sourceTimeStamp = DateTime.MinValue;
                    readItemResults.m_serverTimeStamp = DateTime.MinValue;
                }
                readResults.Add(readItemResults);
            }
            m_ReadEventHandler(asyncReadNodeName, readResults);
            return response.ResponseHeader;
        }

        public static void ValidateResponse(ResponseHeader header)
        {
            if (header == null)
            {
                throw new ServiceResultException(StatusCodes.BadUnknownResponse, "Deficiencies in the response.");
            }

            if (StatusCode.IsBad(header.ServiceResult))
            {
                throw new ServiceResultException(new ServiceResult(header.ServiceResult, header.ServiceDiagnostics, header.StringTable));
            }
        }

        public void RegisterReadEventHandler(onAsyncReadCompleteDelegate eventHandler)
        {
            m_ReadEventHandler = eventHandler; 
        }

        public void UnRegisterReadEventHandler(onAsyncReadCompleteDelegate eventHandler)
        {
            m_ReadEventHandler -= eventHandler; 
        }

        public bool ASyncWrite(List<NodeId> writeNodeIdList, List<object> writeValueList)
        {
            RequestHeader AsyncWriteRequestHeader = null;
            WriteValueCollection nodesToAsyncWrite = new WriteValueCollection();
            try
            {
                for (int i = 0; i < writeNodeIdList.Count(); i++)
                {
                    WriteValue valueToAsyncWrite = new WriteValue();
                    valueToAsyncWrite.NodeId = writeNodeIdList[i];
                    TypeInfo typeInfo = TypeInfo.Construct(writeValueList[i]);
                    valueToAsyncWrite.Value.Value = writeValueList[i];
                    valueToAsyncWrite.AttributeId = (uint)Attributes.Value;
                    valueToAsyncWrite.Value.StatusCode = StatusCodes.Good;
                    valueToAsyncWrite.Value.ServerTimestamp = DateTime.MinValue;
                    valueToAsyncWrite.Value.SourceTimestamp = DateTime.MinValue;
                    nodesToAsyncWrite.Add(valueToAsyncWrite);
                }
                m_clientSession.BeginWrite(AsyncWriteRequestHeader, nodesToAsyncWrite, new AsyncCallback(AsyncWriteCompleted), nodesToAsyncWrite);
            }
            catch (Exception ex)
            {
                Console.WriteLine(" ASyncWrite Exception" + ex.Message);
                return false;
            }
            return true;
        }

        public void AsyncWriteCompleted(IAsyncResult result)
        {
            try
            {
                if (!result.IsCompleted)
                {
                    return;
                }
                EndWrite(result);
            }
            catch (Exception ex)
            {
                Console.WriteLine(" ASyncWrite Exception" + ex.Message);
            }
        }

        public ResponseHeader EndWrite(IAsyncResult result)
        {
            WriteResponse response = null;
            StatusCodeCollection results = new StatusCodeCollection();
            DiagnosticInfoCollection diagnosticInfos = new DiagnosticInfoCollection();
            WriteValueCollection nodesToWrite = (WriteValueCollection)result.AsyncState;
            List<WriteItemResults> writeResults = new List<WriteItemResults>();

            IServiceResponse genericResponse = m_clientSession.TransportChannel.EndSendRequest(result);

            if (genericResponse == null)
            {
                throw new ServiceResultException(StatusCodes.BadUnknownResponse);
            }

            ValidateResponse(genericResponse.ResponseHeader);
            response = (WriteResponse)genericResponse;

            results = response.Results;
            diagnosticInfos = response.DiagnosticInfos;

            List<string> asyncWriteNodeName = new List<string>();
            WriteItemResults writeItemResults = new WriteItemResults();
            writeItemResults.m_resultCodes = new StatusCode();

            for (int ii = 0; ii < results.Count; ii++)
            {
                asyncWriteNodeName.Add(nodesToWrite[ii].NodeId.ToString());
                writeItemResults.m_resultCodes = results[ii];
                writeResults.Add(writeItemResults);
            }

            m_WriteEventHandler(asyncWriteNodeName, writeResults);
            return response.ResponseHeader;
        }

        public void RegisterWriteEventHandler(onAsyncWriteCompleteDelegate eventHandler)
        {
            m_WriteEventHandler = eventHandler;  
        }

        public void UnRegisterWriteEventHandler(onAsyncReadCompleteDelegate eventHandler)
        {
            m_ReadEventHandler = null;  
        }

        public bool CreateSubscription(string sSubscriptionName, int nPublishInterval)
        {
            Subscription subscription = new Subscription(m_clientSession.DefaultSubscription);
            subscription.DisplayName = sSubscriptionName;
            subscription.PublishingInterval = nPublishInterval;
            subscription.LifetimeCount = 100;
            subscription.KeepAliveCount = 10;
            subscription.MaxNotificationsPerPublish = 1000;
            subscription.Priority = 1;
            subscription.PublishingEnabled = true; 
            subscription.TimestampsToReturn = TimestampsToReturn.Both;

            if (m_clientSession.AddSubscription(subscription))
            {
                subscription.Create();
                m_subscriptions.Add(subscription);
                m_subscriptionMap.Add(sSubscriptionName, subscription);
                return true;
            }
            else
            {
                return false;
            }
        }


        public bool DestroySubscription(string sSubscriptionName)
        {
            Subscription subscription = null;
            if (m_subscriptionMap.ContainsKey(sSubscriptionName))
            {
                subscription = m_subscriptionMap[sSubscriptionName];

                if (RemoveAllMonitoredItems(sSubscriptionName))   
                {

                    if (m_clientSession.RemoveSubscription(subscription))
                    {
                        m_subscriptionMap.Remove(sSubscriptionName);    
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }


        public bool AddMonitoredItem(string sSubscriptionName, List<NodeId> NodeIdList)
        {
            Subscription subscription = null;
            if (m_subscriptionMap.ContainsKey(sSubscriptionName))
                subscription = m_subscriptionMap[sSubscriptionName];

            try
            {
                for (int count = 0; count < NodeIdList.Count(); count++)
                {

                    MonitoredItem monitoredItem = new MonitoredItem(subscription.DefaultItem);  
                    monitoredItem.StartNodeId = NodeIdList[count];
                    string monitoredItemName = "MonitoredItem_" + count.ToString();
                    monitoredItem.AttributeId = Attributes.Value;                               
                    monitoredItem.DisplayName = monitoredItemName;
                    monitoredItem.MonitoringMode = MonitoringMode.Reporting;                    
                    monitoredItem.SamplingInterval = subscription.PublishingInterval;
                    monitoredItem.QueueSize = 0;
                    monitoredItem.DiscardOldest = true;

                    if (Contains(subscription, monitoredItem))
                    {
                        Console.WriteLine("The item is already added.");
                    }
                    subscription.AddItem(monitoredItem);                                        
                    monitoredItem.Handle = this;
                    subscription.ApplyChanges();                                                

                    if (ServiceResult.IsBad(monitoredItem.Status.Error))
                    {
                        throw new ServiceResultException(monitoredItem.Status.Error);
                    }
                    monitoredItem.Notification += monitoredItem_Notification;
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine(" AddMonitoredItem Exception" + ex.Message);
                return false;
            }
            return true;
        }

        public void RegisterMontioredItemEventHandler(monitoredItemNotification eventHandler)
        {
            m_MonitoredEventHandler = eventHandler; 
        }

        public void UnRegisterMontioredItemEventHandler(monitoredItemNotification eventHandler)
        {
            m_MonitoredEventHandler = null;  
        }

        public void monitoredItem_Notification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e)
        {
            List<string> monitoredItems = new List<string>();
            List<object> monitoredValues = new List<object>();
            MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification;
            IList<DataValue> list = monitoredItem.DequeueValues();
            DataValue data = list[0];
            monitoredItems.Add(monitoredItem.DisplayName.ToString());
            monitoredValues.Add(data.Value);
            m_MonitoredEventHandler(monitoredItems, monitoredValues);
        }

        public bool RemoveMonitoredItems(string sSubscriptionName, List<NodeId> NodeIdList)
        {
            Subscription subscription = null;
            if (m_subscriptionMap.ContainsKey(sSubscriptionName))
                subscription = m_subscriptionMap[sSubscriptionName];

            for (int count = 0; count < NodeIdList.Count(); count++)
            {
                foreach (MonitoredItem item in subscription.MonitoredItems)
                {
                    if (NodeIdList[count] == item.StartNodeId)
                    {

                        Subscription removeSubscription = item.Subscription;
                        item.Subscription.RemoveItem(item);
                        removeSubscription.ApplyChanges();
                    }
                }
            }
            return true;
        }

        public bool RemoveAllMonitoredItems(string sSubscriptionName)
        {
            Subscription subscription = null;
            if (m_subscriptionMap.ContainsKey(sSubscriptionName))
                subscription = m_subscriptionMap[sSubscriptionName];

            foreach (MonitoredItem item in subscription.MonitoredItems)
            {
                MonitoredItem monitoredItem = item as MonitoredItem;
                if (monitoredItem != null)
                {
                    Subscription removeSubscription = monitoredItem.Subscription;
                    monitoredItem.Subscription.RemoveItem(monitoredItem);
                    removeSubscription.ApplyChanges();
                }
            }
            return true;
        }

        public static bool Contains(Subscription subscription, MonitoredItem monitoredItem)
        {
            foreach (MonitoredItem item in subscription.MonitoredItems)
            {
                if (item.StartNodeId == monitoredItem.StartNodeId)
                {
                    return true;
                }
            }
            return false;
        }

    }
}

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐