Online Forums
Technical support is provided through Support Forums below. Anybody can view them; you need to Register/Login to our site (see links in upper right corner) in order to Post questions. You do not have to be a licensed user of our product.
Please read Rules for forum posts before reporting your issue or asking a question. OPC Labs team is actively monitoring the forums, and replies as soon as possible. Various technical information can also be found in our Knowledge Base. For your convenience, we have also assembled a Frequently Asked Questions page.
Do not use the Contact page for technical issues.
Dynamically Creating Client Objects
You have multiple options to recognize the event notifications one from another:
1. Each incoming event notification has Arguments property, and in it, it has everything you have specified when subscribing - including the EndpointDescriptor and NodeDescriptor. This approach usually requires some kind of lookup or comparison in the code to tell which notification belong where - it works, but is less effective
2. You can specify the State object when making the subscription - differently for each subscription - and the State can already contain whatever data you need to handle *that* particular subscription. I would say that this is the recommended, and also most natural and most used approach.
3. You can use callbacks instead of events. The event handler is "global" for the instance of EasyUAClient, but the callback is specified with each subscription. This means that a whole different code can be hooked to each subscription.
Example for #2 (the example uses 3 nodes on the same server, but they can be on different servers too):
// This example shows how to subscribe to changes of multiple monitored items
// and display each change, identifying the different subscriptions by an
// object.
using System;
using System.Threading;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.OperationModel;
namespace UADocExamples._EasyUAClient
{
partial class SubscribeMultipleMonitoredItems
{
class CustomObject
{
public CustomObject(string name)
{
Name = name;
}
public string Name { get; }
}
public static void StateAsObject()
{
UAEndpointDescriptor endpointDescriptor =
"opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
// or "http://opcua.demo-this.com:51211/UA/SampleServer" (not in .NET Standard)
// or "https://opcua.demo-this.com:51212/UA/SampleServer/"
// Instantiate the client object and hook events
var client = new EasyUAClient();
client.DataChangeNotification += ClientOnDataChangeNotification_StateAsObject;
Console.WriteLine("Subscribing...");
int[] handleArray = client.SubscribeMultipleMonitoredItems(new[]
{
new EasyUAMonitoredItemArguments(null, endpointDescriptor,
"nsu=http://test.org/UA/Data/;i=10845", 1000)
{State = new CustomObject("First")}, // A custom object that corresponds to the subscription
new EasyUAMonitoredItemArguments(null, endpointDescriptor,
"nsu=http://test.org/UA/Data/;i=10853", 1000)
{State = new CustomObject("Second")}, // A custom object that corresponds to the subscription
new EasyUAMonitoredItemArguments(null, endpointDescriptor,
"nsu=http://test.org/UA/Data/;i=10855", 1000)
{State = new CustomObject("Third")}, // A custom object that corresponds to the subscription
});
for (int i = 0; i < handleArray.Length; i++)
Console.WriteLine($"handleArray[{i}]: {handleArray[i]}");
Console.WriteLine("Processing monitored item changed events for 10 seconds...");
Thread.Sleep(10 * 1000);
Console.WriteLine("Unsubscribing...");
client.UnsubscribeAllMonitoredItems();
Console.WriteLine("Waiting for 5 seconds...");
Thread.Sleep(5 * 1000);
Console.WriteLine("Finished.");
}
static void ClientOnDataChangeNotification_StateAsObject(object sender, EasyUADataChangeNotificationEventArgs eventArgs)
{
// Obtain the custom object we have passed in.
var stateAsObject = (CustomObject) eventArgs.Arguments.State;
// Display the data
if (eventArgs.Succeeded)
Console.WriteLine($"{stateAsObject.Name}: {eventArgs.AttributeData}");
else
Console.WriteLine($"{stateAsObject.Name} *** Failure: {eventArgs.ErrorMessageBrief}");
}
Best regards
Please Log in or Create an account to join the conversation.
This clarifies a lot of things we were struggling with.
Now, out of curiosity, if I were to subscribeTomultiple to both of the servers with the same client object, is there a way to separate each server's connection onDatachange handler or I will need to do everything through the same handler?
Thank you again, and best regards.
Please Log in or Create an account to join the conversation.
does this help?
// This example shows that either a single client object, or multiple client objects can be used to read values from two
// servers.
using System;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.OperationModel;
namespace UADocExamples._EasyUAClient
{
partial class ReadValue
{
public static void MultipleServers()
{
// Define which servers we will work with.
UAEndpointDescriptor endpointDescriptor1 =
"opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
// or "http://opcua.demo-this.com:51211/UA/SampleServer" (not in .NET Standard)
// or "https://opcua.demo-this.com:51212/UA/SampleServer/"
UAEndpointDescriptor endpointDescriptor2 =
"opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer";
// Part 1: Use a single client object.
// This demonstrates the fact the the client objects do *not* represent connections to individual servers.
// Instead, they are able to maintain connections to multiple servers internally. API method calls on the client
// object include the server's endpoint descriptor in their arguments, so you can specify a different endpoint
// with each operation.
Console.WriteLine();
// Instantiate the client object
var client = new EasyUAClient();
Console.WriteLine("Obtaining values of nodes using a single client object...");
object value1, value2;
try
{
// The node Id we are reading returns the product name of the server.
value1 = client.ReadValue(endpointDescriptor1, "nsu=http://opcfoundation.org/UA/ ;i=2261");
value2 = client.ReadValue(endpointDescriptor2, "nsu=http://opcfoundation.org/UA/ ;i=2261");
// Note: For efficiency (reading from the two servers in parallel), it would be better to use the
// ReadMultipleValues method here, but this example is made for code clarity.
}
catch (UAException uaException)
{
Console.WriteLine("*** Failure: {0}", uaException.GetBaseException().Message);
return;
}
// Display results
Console.WriteLine("value1: {0}", value1);
Console.WriteLine("value2: {0}", value2);
// Part 2: Use multiple client objects.
// This demonstrates the fact that it is also possible to use multiple client objects, and on the OPC side, the
// behavior will be the same as if you had used a single client object. Multiple client objects consume somewhat
// more resources on the client side, but they come handy if, for example,
// - you cannot easily pass around the single pre-created client object to various parts in your code, or
// - you are using subscriptions and you want to hook separate event handlers for different purposes, or
// - you need to set something in the instance parameters of the client object differently for different
// connections.
Console.WriteLine();
// Instantiate the client object2
var client1 = new EasyUAClient();
var client2 = new EasyUAClient();
Console.WriteLine("Obtaining values of nodes using a single client object...");
try
{
// The node Id we are reading returns the product name of the server.
value1 = client1.ReadValue(endpointDescriptor1, "nsu=http://opcfoundation.org/UA/ ;i=2261");
value2 = client2.ReadValue(endpointDescriptor2, "nsu=http://opcfoundation.org/UA/ ;i=2261");
}
catch (UAException uaException)
{
Console.WriteLine("*** Failure: {0}", uaException.GetBaseException().Message);
return;
}
// Display results
Console.WriteLine("value1: {0}", value1);
Console.WriteLine("value2: {0}", value2);
// Example output:
//
//Obtaining values of nodes using a single client object...
//value1: OPC UA SDK Samples
//value2: OPC UA Workshop Samples
//
//Obtaining values of nodes using a single client object...
//value1: OPC UA SDK Samples
//value2: OPC UA Workshop Samples
}
}
}
Best regards
Please Log in or Create an account to join the conversation.
The customer is attempting to connect to two different servers. We would like to know the most efficient way to accomplish this. I fear that I am not understanding how you can do so with one client instance. Would you mind sharing an example?
Thank you again.
Please Log in or Create an account to join the conversation.
Before we get to the actual code, I want to clarify the requirements, and make sure this has been considered: opclabs.doc-that.com/files/onlinedocs/QuickOpc/Latest/User%2...ients%20and%20Subscribers.html .
Basically, under normal circumstances, the developer can use one EasyUAClient instance to connect to multiple servers, *or* he can use multiple instances, and there won't be much difference (the differences are in how to object behaves in relation to the developer's code - e.g. each will have its own events - but connections maintained to the target servers will be *identical* in these two approaches!).
The only reasons to use the "Isolated=true" setting I can imagine are:
- There are EasyUAClient parameters that are normally shared, but the developer wants to use different parameters with different servers, or
- the developer wants to create multiple connections (sessions) to the same server (this is generally discouraged, and although there can be some rare, valid reason to do that, I would like to know what the reason is, if this is the case).
From the formulation of your question, I got somewhat suspicious, because it is not apparent why the customer wants multiple client objects (although he can...), and also not why he has chosen to make them "isolated".
Thank you
Please Log in or Create an account to join the conversation.
What is the best practice for dynamically instantiating client objects?
I had a customer reach out who would like to have multiple connections to multiple servers using multiple client objects.
I have attached a screenshot of how the customer initially tried this. Unfortunately, the object is overwritten each time the For Each loop is entered this way. For the time being, we are having him statically define two client objects.
Please Log in or Create an account to join the conversation.