C# 从OPC.NET服务器返回的ObjectAttributes实例错误地将IsCollectionHistory属性标识为false 我使用XI接口从OPC.NET服务器检索数据。但我遇到的问题是,服务器似乎错误地将参数标识为未被历史化

C# 从OPC.NET服务器返回的ObjectAttributes实例错误地将IsCollectionHistory属性标识为false 我使用XI接口从OPC.NET服务器检索数据。但我遇到的问题是,服务器似乎错误地将参数标识为未被历史化,c#,opc,C#,Opc,尽管来自DeltaV的所有信息都表明从服务器返回的ObjectAttributes对象的相应参数应该表明它正在收集历史,但IsCollectionHistory属性实际上表明它是false 已启用历史记录收集: 相关参数位于历史记录集合中: 我不会包括截图,但我也可以打开该参数的历史趋势。但正如您在下面看到的,当我在调试时检查检索到的对象时,它说它没有被历史化 以下是我正在使用的一些代码: FindCriteria criteria = createCriteria(path, false

尽管来自DeltaV的所有信息都表明从服务器返回的ObjectAttributes对象的相应参数应该表明它正在收集历史,但IsCollectionHistory属性实际上表明它是false

已启用历史记录收集:

相关参数位于历史记录集合中:

我不会包括截图,但我也可以打开该参数的历史趋势。但正如您在下面看到的,当我在调试时检查检索到的对象时,它说它没有被历史化

以下是我正在使用的一些代码:

FindCriteria criteria = createCriteria(path, false);
List<Parameter> parameters = new List<Parameter>();
IEnumerable<ObjectAttributes> enumerableObject;
int i = 0;
try 
{ 
    enumerableObject = iContext.FindObjects(criteria, 50); 
}
catch (System.ServiceModel.FaultException)
{
    //This error is thrown when no data is returned.
    return null;
}
你知道我哪里出了问题吗

编辑:

尝试MotteAndBailey的答案后,调用AddNewDataObjectToDataJournalList时抛出一个错误。与之相关的消息是“OPC HDA创建浏览失败”

下面是使用HDAprobe时消息框中错误的屏幕截图:

有关OPC.NET中属性的一些信息-

席服务器封装OPCDA和OPCHDA服务器。每台服务器上可用的项目属性(属性)以及使用Classic(DCOM)OPC访问它们的方式有很大不同

OPCDA

OPCDA服务器提供了一种确定项目属性的方法: IOPCItemProperties::GetItemProperties()

此调用为客户端提供了一种使用项目ID(服务器地址空间中项目的字符串路径)和propertyID读取项目所有属性值的方法。席服务器在执行FiffObjutsS.()调用时使用此调用。FindObjects()返回OPCDA服务器为项目公开的所有属性

OPCHDA

OPCHDA服务器有一个确定项目属性的方法,但它需要项目句柄,而不是项目ID/路径:
IOPCHDA_SyncRead::ReadAttribute()

结果,席因对象()通过XI调用OpCHDA服务器只返回项ID属性。其他属性设置为默认值。要确定其他属性的实际值,用户必须将该项添加到列表中,并对他们希望看到的特定属性调用ReadAttribute()

总之,OPCDA服务器的工作原理与您预期的非常相似,并在单个方法调用中返回对象属性;但是,OPCHDA服务器需要额外的步骤来获取所有对象属性

示例代码将生成仅带有ON扫描历史项的席日记列表。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Xi.Client.Base.API;
using Xi.Client.Base;
using Xi.Contracts;
using Xi.Contracts.Data;
using Xi.Contracts.Constants;
using System.ServiceModel.Description;
using Xi.Client.CommonDialogs;
using System.Runtime.Serialization;


namespace ConsoleFindObjectsHDA
{
    public class DotNetSupport
    {
        IXiEndpointDiscovery iEndpointDiscovery;
        IXiContext iContext;
        IXiEndpointBase readEndpoint;

        ServiceEndpoint RMSvcEndpt;

        //the list of items the user is trying to read
        IXiDataJournalList iDataJournalList;

        public void GetSomeData()
        {
            //get a connection to an OPC.NET server
            if (Connect())
            {
                //we have to have a list to add a tag to and hold returned datasets
                if (CreateJournalList())
                {
                    //now use the list to add items and read their attributes - only "good" ones will be left on the list
                    ListAllHDAItemsOnScan();

                    if (iDataJournalList.Count() > 0)
                    {
                        //at this point we <should> have a DataJournalList containing only the HDA items on scan
                        //we can use the normal data read methods to get history for the items if we wish

                        //  <do some history thing here>
                    }
                    else
                    {
                        Console.WriteLine("\nThere were no points on-scan in the historian");
                    }

                    Console.WriteLine("\nPress <return> to exit program");
                    Console.ReadLine();
                }

                ////clean up if we have open connections/contexts
                Cleanup();
            }

        }

        //we will use FindObjects to browse all the leaves in the HDA server, then add them one-by-one to a datalist
        //when we query their on-scan property and it is true we leave them on the list
        //...if not, we remove them (giving us a list of the good HDA points)
        void ListAllHDAItemsOnScan()
        {
            FindCriteria criteria = GetLeafCriteria(); 
            IEnumerable<ObjectAttributes> enumerableObject;

            try
            {
                //ask the server for a list of leaves...up to 50 max returned in this call
                enumerableObject = iContext.FindObjects(criteria, 50);

                //for each string itemID: add it to the list, read the attribute, and remove it from the list if not on-scan
                foreach (ObjectAttributes oa in enumerableObject)
                {
                    //we do not have to commit this because we have indicated the operation is NOT prep-only
                    Console.WriteLine("Adding OPCHDA item {0}.", oa.InstanceId.LocalId);
                    IXiHistoricalDataObject ixObject = iDataJournalList.AddNewDataObjectToDataJournalList(oa.InstanceId, false);   

                    //we are getting the CURRENT (from NOW -to- NOW) item status
                    FilterCriterion fc1 = GetFilterCriteriaDateTime(DateTime.Now); 

                    //tell the server what property (attribute) we want to read
                    List<TypeId> lstp = new List<TypeId>();
                    TypeId typeit = new TypeId("", "", DVServerAttributes.DELTAV_DVCH_ON_SCAN.ToString());
                    lstp.Add(typeit);

                    //read the property from the server
                    iDataJournalList.ReadJournalDataProperties(fc1, fc1, ixObject, lstp);

                    //find the current item and check it for "on-scan"
                    if (ixObject != null)
                    {
                        if (ixObject.PropertyValues.First().PropertyValues.UintValues.First() == 1)
                        {
                            Console.WriteLine("OPCHDA item {0} is on-scan.\n", oa.InstanceId.LocalId);
                        }
                        else
                        {
                            if (ixObject.PrepForRemove())
                            {
                                Console.WriteLine("OPCHDA item {0} is not on-scan. Removing item.\n", oa.InstanceId.LocalId);
                                iDataJournalList.CommitRemoveableElements();
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception in FindObjects(). The exception is:{0}\n", ex.Message);
            }

        }


        //create a filtercriterion for a specific date time - this is an EQUAL (not > or <) comparison operator
        public FilterCriterion GetFilterCriteriaDateTime(DateTime dtChosenTime)
        {
            //simple timestamp filter which is used by the read call
            FilterCriterion filterCriterion = null;

            // this is a timestamp
            string filterOperand = FilterOperandNames.Timestamp;

            //make the given time with UTC/Local set to local time just to be sure
            DateTime dtTmp1 = DateTime.SpecifyKind(dtChosenTime, DateTimeKind.Local);
            object comparisonValue = dtTmp1;

            //timestamp equal to this one 
            uint oper = FilterOperator.Equal;

            //create the filter
            filterCriterion = new FilterCriterion()
            {
                OperandName = filterOperand,
                Operator = oper,
                ComparisonValue = comparisonValue,
            };

            return filterCriterion;
        }

        //create a filtercriterion for leaves (OPCHDA items)
        public FilterCriterion GetLeafFilterCriterion()
        {
            //simple filter for leaves 
            FilterCriterion filterCriterion = null;

            // what this criterion applies to
            string filterOperand = FilterOperandNames.BranchOrLeaf;

            //Must equal "LEAF" to match
            uint oper = FilterOperator.Equal;

            //create the filter
            filterCriterion = new FilterCriterion()
            {
                OperandName = filterOperand,
                Operator = oper,
                ComparisonValue = "LEAF",
            };

            return filterCriterion;
        }

        //set up the FindCriteria search of the server  
        public FindCriteria GetLeafCriteria()
        {
            FindCriteria findCriteria = null;
            findCriteria = new FindCriteria();

            //our browse starts at the root - NULL means "continue browsing from where you are"
            findCriteria.StartingPath = new ObjectPath("//", "HDA");

            //a list of OR-ed filter criteria (we have only one)
            ORedFilters orthefilters = new ORedFilters();

            //the FilterCriteria list (there is only one criterion)
            orthefilters.FilterCriteria = new List<FilterCriterion>();
            orthefilters.FilterCriteria.Add(GetLeafFilterCriterion());  //we want leaves

            //add our OR-ed filter to the filterset filters list (whew!)
            findCriteria.FilterSet = new FilterSet();
            findCriteria.FilterSet.Filters = new List<ORedFilters>();
            findCriteria.FilterSet.Filters.Add(orthefilters);

            return findCriteria;
        }


        //connect to the OPC.NET server and get a read endpoint
        public bool Connect()
        {
            //set this to point to your OPC.Net server
            string serverUrl = "http://localhost:58080/XiServices/ServerDiscovery";

            bool bReturnVal = false;

            try
            {
                Console.WriteLine("Getting Endpoint Discovery from server:\n{0}\n", serverUrl);

                //This class is used to locate a server and obtain its list of ServiceEndpoints.
                iEndpointDiscovery = new XiEndpointDiscovery(serverUrl) as IXiEndpointDiscovery;

                //we have the server...now check for endpoints
                //there should always be TCP endpoints for a DeltaV OPC.NET server so we do not search HTTP and Named Pipes to find one
                //and we do not consider choosing the fastest option between the three (TCP/HTTP/NamedPipes). We just use the TCP/IP one.

                // GetServiceEndpointsByBinding searches the list of endpoints on the XiEndpointDiscovery connection with the specified contractType and binding type.
                // We use the ResourceManagement endpoint to find the the other open endpoints on the server (some might be disabled)
                IEnumerable<ServiceEndpoint> resourceEndpoints = iEndpointDiscovery.GetServiceEndpointsByBinding(typeof(IResourceManagement).Name, typeof(System.ServiceModel.NetTcpBinding));

                //use the first (probably only) resource endpoint for TCP/IP to open a context between client and server
                if ((resourceEndpoints != null) && (resourceEndpoints.Count() > 0))
                {

                    var serviceEndpoints = resourceEndpoints as IList<ServiceEndpoint> ?? resourceEndpoints.ToList();


                    //pick the first RM endpoint we found
                    RMSvcEndpt = ((IList<ServiceEndpoint>)serviceEndpoints).First();

                    //Open the Context using the RM endpoint and some other values including timeout, what we want to read (HDA), and the GUID for this context
                    Console.WriteLine("Opening Client Context with Initiate\n");
                    iContext = XiContext.Initiate(RMSvcEndpt,
                                                        iEndpointDiscovery.ServerEntry,
                                                        300000,
                                                        (uint)ContextOptions.EnableJournalDataAccess,   //HDA
                                                        (uint)System.Threading.Thread.CurrentThread.CurrentCulture.LCID,
                                                        Guid.NewGuid().ToString());

                    if (iContext != null)
                    {

                        //find a read endpoint using the XiEndpointDiscovery connection
                        IEnumerable<ServiceEndpoint> readseps = iEndpointDiscovery.GetServiceEndpointsByBinding(typeof(IRead).Name, RMSvcEndpt.Binding.GetType());

                        //if we found at least one read endpoint, connect the context to it
                        readEndpoint = null;
                        if (readseps != null)
                        {
                            Console.WriteLine("Adding Read endpoint to Context\n");
                            ServiceEndpoint sep = readseps.ElementAt<ServiceEndpoint>(0);
                            readEndpoint = iContext.OpenEndpoint(sep, 30000, new TimeSpan(5000));

                            if (readEndpoint != null)
                            {
                                bReturnVal = true;        //everything went OK
                            }
                            else
                            {
                                Console.WriteLine("Unable to add Read endpoint to Context\n");
                                bReturnVal = false;        //failed
                            }

                        }
                    }
                    else
                    {
                        Console.WriteLine("Unable to open Client Context\n");
                        bReturnVal = false;
                    }
                }

            }
            catch (Exception)
            {
                bReturnVal = false;
            }

            return (bReturnVal);
        }


        public bool CreateJournalList()
        {
            bool retval = false;

            try
            {
                //create a new list of HDA objects for this read
                //                                             update  buffer  
                //                                             rate    rate   filterset(not used here)
                iDataJournalList = iContext.NewDataJournalList(1000,   1000,  null);

                if (iDataJournalList != null)
                {
                    //we need to add the list to a read endpoint to give it data access
                    iDataJournalList.AddListToEndpoint(readEndpoint);

                    //enable the list so we can connect the items we add to it and read data
                    iDataJournalList.EnableListUpdating(true);

                    retval = true;
                }
            }
            catch (Exception)
            {
                retval = false;
            }

            return retval;
        }


        public void Cleanup()
        {
            if (iContext != null)
            {
                iContext.Dispose();
            }

        }

    } //class DotNetSupport
}

namespace ConsoleFindObjectsHDA
{
    public class DVServerAttributes
    {
        //some DeltaV-specific OPCHDA attributes
        public static uint DELTAV_DESC               = 2147483650;
        public static uint DELTAV_ENG_UNITS          = 2147483651;
        public static uint DELTAV_EU100              = 2147483666;
        public static uint DELTAV_EU0                = 2147483667;
        public static uint DELTAV_DVCH_LAST_DOWNLOAD = 2147483682;
        public static uint DELTAV_DVCH_ON_SCAN       = 2147483683;
        public static uint DELTAV_NAMED_SET          = 2147483698;
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用X.clit.BaseAPI;
使用X.clit.BASE;
使用席。
使用X.合同数据;
使用X.Currists.常数;
使用System.ServiceModel.Description;
使用X.clion。
使用System.Runtime.Serialization;
命名空间ConsoleFindObjectsHDA
{
公共类DotNetSupport
{
Ixendpointdiscovery iEndpointDiscovery;
IXiContext-iContext;
IXiEndpointBase readEndpoint;
ServiceEndpoint RMSvcEndpt;
//用户试图读取的项目列表
IxidatJournallist IdatJournallist;
public void GetSomeData()
{
//获取到OPC.NET服务器的连接
if(Connect())
{
//我们必须有一个列表来添加标记并保存返回的数据集
if(CreateJournalList())
{
//现在使用列表添加项目并读取其属性-列表中只剩下“好”项目
ListAllHDAItemsOnScan();
如果(IDataJournallList.Count()>0)
{
//此时,我们有一个DataJournalList,它只包含扫描中的HDA项
//如果愿意,我们可以使用常规数据读取方法获取项目的历史记录
//  
}
其他的
{
Console.WriteLine(“historian中扫描时没有点”);
}
Console.WriteLine(“\n按退出程序”);
Console.ReadLine();
}
////如果我们有打开的连接/上下文,请清理
清理();
}
}
//我们将使用FindObjects浏览HDA服务器中的所有叶子,然后将它们逐个添加到数据列表中
//当我们查询它们的on scan属性时,如果是真的,我们会将它们保留在列表中
//…如果没有,我们将删除它们(给我们一个良好的HDA分数列表)
void ListAllHDAItemsOnScan()
{
FindCriteria条件=GetLeafCriteria();
IEnumerable可枚举对象;
尝试
{
//请求服务器提供此呼叫中最多返回50个叶子的列表
enumerableObject=iContext.FindObjects(标准,50);
//对于每个字符串itemID:将其添加到列表中,读取属性,如果不在扫描中,则将其从列表中删除
foreach(enumerableObject中的ObjectAttributes oa)
{
//我们不必提交此操作,因为我们已经指出该操作不仅仅是prep
WriteLine(“添加OPCHDA项{0}.”,oa.InstanceId.LocalId);
IXiHistoricalDataObject ixObject=IDataJournallList.AddNewDataObjectToDataJournallList(oa.InstanceId,false);
//我们正在获取当前(从现在到现在)项目状态
过滤器标准fc1=GetFi
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Xi.Client.Base.API;
using Xi.Client.Base;
using Xi.Contracts;
using Xi.Contracts.Data;
using Xi.Contracts.Constants;
using System.ServiceModel.Description;
using Xi.Client.CommonDialogs;
using System.Runtime.Serialization;


namespace ConsoleFindObjectsHDA
{
    public class DotNetSupport
    {
        IXiEndpointDiscovery iEndpointDiscovery;
        IXiContext iContext;
        IXiEndpointBase readEndpoint;

        ServiceEndpoint RMSvcEndpt;

        //the list of items the user is trying to read
        IXiDataJournalList iDataJournalList;

        public void GetSomeData()
        {
            //get a connection to an OPC.NET server
            if (Connect())
            {
                //we have to have a list to add a tag to and hold returned datasets
                if (CreateJournalList())
                {
                    //now use the list to add items and read their attributes - only "good" ones will be left on the list
                    ListAllHDAItemsOnScan();

                    if (iDataJournalList.Count() > 0)
                    {
                        //at this point we <should> have a DataJournalList containing only the HDA items on scan
                        //we can use the normal data read methods to get history for the items if we wish

                        //  <do some history thing here>
                    }
                    else
                    {
                        Console.WriteLine("\nThere were no points on-scan in the historian");
                    }

                    Console.WriteLine("\nPress <return> to exit program");
                    Console.ReadLine();
                }

                ////clean up if we have open connections/contexts
                Cleanup();
            }

        }

        //we will use FindObjects to browse all the leaves in the HDA server, then add them one-by-one to a datalist
        //when we query their on-scan property and it is true we leave them on the list
        //...if not, we remove them (giving us a list of the good HDA points)
        void ListAllHDAItemsOnScan()
        {
            FindCriteria criteria = GetLeafCriteria(); 
            IEnumerable<ObjectAttributes> enumerableObject;

            try
            {
                //ask the server for a list of leaves...up to 50 max returned in this call
                enumerableObject = iContext.FindObjects(criteria, 50);

                //for each string itemID: add it to the list, read the attribute, and remove it from the list if not on-scan
                foreach (ObjectAttributes oa in enumerableObject)
                {
                    //we do not have to commit this because we have indicated the operation is NOT prep-only
                    Console.WriteLine("Adding OPCHDA item {0}.", oa.InstanceId.LocalId);
                    IXiHistoricalDataObject ixObject = iDataJournalList.AddNewDataObjectToDataJournalList(oa.InstanceId, false);   

                    //we are getting the CURRENT (from NOW -to- NOW) item status
                    FilterCriterion fc1 = GetFilterCriteriaDateTime(DateTime.Now); 

                    //tell the server what property (attribute) we want to read
                    List<TypeId> lstp = new List<TypeId>();
                    TypeId typeit = new TypeId("", "", DVServerAttributes.DELTAV_DVCH_ON_SCAN.ToString());
                    lstp.Add(typeit);

                    //read the property from the server
                    iDataJournalList.ReadJournalDataProperties(fc1, fc1, ixObject, lstp);

                    //find the current item and check it for "on-scan"
                    if (ixObject != null)
                    {
                        if (ixObject.PropertyValues.First().PropertyValues.UintValues.First() == 1)
                        {
                            Console.WriteLine("OPCHDA item {0} is on-scan.\n", oa.InstanceId.LocalId);
                        }
                        else
                        {
                            if (ixObject.PrepForRemove())
                            {
                                Console.WriteLine("OPCHDA item {0} is not on-scan. Removing item.\n", oa.InstanceId.LocalId);
                                iDataJournalList.CommitRemoveableElements();
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception in FindObjects(). The exception is:{0}\n", ex.Message);
            }

        }


        //create a filtercriterion for a specific date time - this is an EQUAL (not > or <) comparison operator
        public FilterCriterion GetFilterCriteriaDateTime(DateTime dtChosenTime)
        {
            //simple timestamp filter which is used by the read call
            FilterCriterion filterCriterion = null;

            // this is a timestamp
            string filterOperand = FilterOperandNames.Timestamp;

            //make the given time with UTC/Local set to local time just to be sure
            DateTime dtTmp1 = DateTime.SpecifyKind(dtChosenTime, DateTimeKind.Local);
            object comparisonValue = dtTmp1;

            //timestamp equal to this one 
            uint oper = FilterOperator.Equal;

            //create the filter
            filterCriterion = new FilterCriterion()
            {
                OperandName = filterOperand,
                Operator = oper,
                ComparisonValue = comparisonValue,
            };

            return filterCriterion;
        }

        //create a filtercriterion for leaves (OPCHDA items)
        public FilterCriterion GetLeafFilterCriterion()
        {
            //simple filter for leaves 
            FilterCriterion filterCriterion = null;

            // what this criterion applies to
            string filterOperand = FilterOperandNames.BranchOrLeaf;

            //Must equal "LEAF" to match
            uint oper = FilterOperator.Equal;

            //create the filter
            filterCriterion = new FilterCriterion()
            {
                OperandName = filterOperand,
                Operator = oper,
                ComparisonValue = "LEAF",
            };

            return filterCriterion;
        }

        //set up the FindCriteria search of the server  
        public FindCriteria GetLeafCriteria()
        {
            FindCriteria findCriteria = null;
            findCriteria = new FindCriteria();

            //our browse starts at the root - NULL means "continue browsing from where you are"
            findCriteria.StartingPath = new ObjectPath("//", "HDA");

            //a list of OR-ed filter criteria (we have only one)
            ORedFilters orthefilters = new ORedFilters();

            //the FilterCriteria list (there is only one criterion)
            orthefilters.FilterCriteria = new List<FilterCriterion>();
            orthefilters.FilterCriteria.Add(GetLeafFilterCriterion());  //we want leaves

            //add our OR-ed filter to the filterset filters list (whew!)
            findCriteria.FilterSet = new FilterSet();
            findCriteria.FilterSet.Filters = new List<ORedFilters>();
            findCriteria.FilterSet.Filters.Add(orthefilters);

            return findCriteria;
        }


        //connect to the OPC.NET server and get a read endpoint
        public bool Connect()
        {
            //set this to point to your OPC.Net server
            string serverUrl = "http://localhost:58080/XiServices/ServerDiscovery";

            bool bReturnVal = false;

            try
            {
                Console.WriteLine("Getting Endpoint Discovery from server:\n{0}\n", serverUrl);

                //This class is used to locate a server and obtain its list of ServiceEndpoints.
                iEndpointDiscovery = new XiEndpointDiscovery(serverUrl) as IXiEndpointDiscovery;

                //we have the server...now check for endpoints
                //there should always be TCP endpoints for a DeltaV OPC.NET server so we do not search HTTP and Named Pipes to find one
                //and we do not consider choosing the fastest option between the three (TCP/HTTP/NamedPipes). We just use the TCP/IP one.

                // GetServiceEndpointsByBinding searches the list of endpoints on the XiEndpointDiscovery connection with the specified contractType and binding type.
                // We use the ResourceManagement endpoint to find the the other open endpoints on the server (some might be disabled)
                IEnumerable<ServiceEndpoint> resourceEndpoints = iEndpointDiscovery.GetServiceEndpointsByBinding(typeof(IResourceManagement).Name, typeof(System.ServiceModel.NetTcpBinding));

                //use the first (probably only) resource endpoint for TCP/IP to open a context between client and server
                if ((resourceEndpoints != null) && (resourceEndpoints.Count() > 0))
                {

                    var serviceEndpoints = resourceEndpoints as IList<ServiceEndpoint> ?? resourceEndpoints.ToList();


                    //pick the first RM endpoint we found
                    RMSvcEndpt = ((IList<ServiceEndpoint>)serviceEndpoints).First();

                    //Open the Context using the RM endpoint and some other values including timeout, what we want to read (HDA), and the GUID for this context
                    Console.WriteLine("Opening Client Context with Initiate\n");
                    iContext = XiContext.Initiate(RMSvcEndpt,
                                                        iEndpointDiscovery.ServerEntry,
                                                        300000,
                                                        (uint)ContextOptions.EnableJournalDataAccess,   //HDA
                                                        (uint)System.Threading.Thread.CurrentThread.CurrentCulture.LCID,
                                                        Guid.NewGuid().ToString());

                    if (iContext != null)
                    {

                        //find a read endpoint using the XiEndpointDiscovery connection
                        IEnumerable<ServiceEndpoint> readseps = iEndpointDiscovery.GetServiceEndpointsByBinding(typeof(IRead).Name, RMSvcEndpt.Binding.GetType());

                        //if we found at least one read endpoint, connect the context to it
                        readEndpoint = null;
                        if (readseps != null)
                        {
                            Console.WriteLine("Adding Read endpoint to Context\n");
                            ServiceEndpoint sep = readseps.ElementAt<ServiceEndpoint>(0);
                            readEndpoint = iContext.OpenEndpoint(sep, 30000, new TimeSpan(5000));

                            if (readEndpoint != null)
                            {
                                bReturnVal = true;        //everything went OK
                            }
                            else
                            {
                                Console.WriteLine("Unable to add Read endpoint to Context\n");
                                bReturnVal = false;        //failed
                            }

                        }
                    }
                    else
                    {
                        Console.WriteLine("Unable to open Client Context\n");
                        bReturnVal = false;
                    }
                }

            }
            catch (Exception)
            {
                bReturnVal = false;
            }

            return (bReturnVal);
        }


        public bool CreateJournalList()
        {
            bool retval = false;

            try
            {
                //create a new list of HDA objects for this read
                //                                             update  buffer  
                //                                             rate    rate   filterset(not used here)
                iDataJournalList = iContext.NewDataJournalList(1000,   1000,  null);

                if (iDataJournalList != null)
                {
                    //we need to add the list to a read endpoint to give it data access
                    iDataJournalList.AddListToEndpoint(readEndpoint);

                    //enable the list so we can connect the items we add to it and read data
                    iDataJournalList.EnableListUpdating(true);

                    retval = true;
                }
            }
            catch (Exception)
            {
                retval = false;
            }

            return retval;
        }


        public void Cleanup()
        {
            if (iContext != null)
            {
                iContext.Dispose();
            }

        }

    } //class DotNetSupport
}

namespace ConsoleFindObjectsHDA
{
    public class DVServerAttributes
    {
        //some DeltaV-specific OPCHDA attributes
        public static uint DELTAV_DESC               = 2147483650;
        public static uint DELTAV_ENG_UNITS          = 2147483651;
        public static uint DELTAV_EU100              = 2147483666;
        public static uint DELTAV_EU0                = 2147483667;
        public static uint DELTAV_DVCH_LAST_DOWNLOAD = 2147483682;
        public static uint DELTAV_DVCH_ON_SCAN       = 2147483683;
        public static uint DELTAV_NAMED_SET          = 2147483698;
    }
}