I have figured out the source of the issue. it appears that if you do not assign an event ID to the events then the issue i described happens, However if you do assign one then it does not. I will be assigning event ids from now on.
I managed to reproduce the issue using the Lesson01 project from the GettingStarted solution you provide with the sdk and swapping out the node manager in there for this one:
Code: Select all
using System;
using System.Timers;
using UnifiedAutomation.UaBase;
using UnifiedAutomation.UaServer;
namespace YourCompany.GettingStarted
{
internal class EventTestNodeManager : BaseNodeManager
{
private Timer _timer;
public EventTestNodeManager(ServerManager server, params string[] namespaceUris) : base(server, namespaceUris)
{
}
private NodeId rootId;
private NodeId o1Id;
private NodeId o2Id;
private NodeId sharedId;
public override void Startup()
{
base.Startup();
DefaultNamespaceIndex = AddNamespaceUri("Http://sample.com");
rootId = new NodeId("Root", DefaultNamespaceIndex);
o1Id = new NodeId("o1", DefaultNamespaceIndex);
o2Id = new NodeId("o2", DefaultNamespaceIndex);
sharedId = new NodeId("oShared", DefaultNamespaceIndex);
//root folder.
var f1 = new CreateObjectSettings()
{
ParentNodeId = ObjectIds.ObjectsFolder,
ReferenceTypeId = ReferenceTypeIds.Organizes,
RequestedNodeId = rootId,
BrowseName = new QualifiedName("EventRoot", DefaultNamespaceIndex),
TypeDefinitionId = ObjectTypeIds.FolderType,
NotifierParent = ObjectIds.Server,
};
CreateObject(Server.DefaultRequestContext, f1);
//o1 as child of root folder
CreateTestObject(o1Id, "Obj1");
//o2 as child of root folder
CreateTestObject(o2Id, "Obj2");
//oShared as child of root
CreateTestObject(sharedId, "ObjShared");
//make obj_shared also a child and notifier of o1 and o2
UpdateParentChildReference(o1Id, sharedId, true);
UpdateNotifierReference(o1Id, sharedId, true);
UpdateParentChildReference(o2Id, sharedId, true);
UpdateNotifierReference(o2Id, sharedId, true);
//remove references for root.
UpdateOrganizesReference(rootId, sharedId, false);
UpdateNotifierReference(rootId, sharedId, false);
_timer = new Timer { Interval = 3000 };
_timer.Elapsed += OnTimerElapsed;
_timer.AutoReset = true;
_timer.Enabled = true;
}
private void CreateTestObject(NodeId requestedId, string name)
{
var oShared = new CreateObjectSettings()
{
ParentNodeId = rootId,
ReferenceTypeId = ReferenceTypeIds.Organizes,
RequestedNodeId = requestedId,
BrowseName = new QualifiedName(name, DefaultNamespaceIndex),
TypeDefinitionId = ObjectTypeIds.BaseObjectType,
EventNotifier = EventNotifiers.SubscribeToEvents,
NotifierParent = rootId, //root is initial notifier parent.
};
//create object with root as notifier parent.
CreateObject(Server.DefaultRequestContext, oShared);
}
private void UpdateNotifierReference(NodeId parent, NodeId child, bool add)
{
if (add)
{
AddReference(Server.DefaultRequestContext, child, ReferenceTypeIds.HasNotifier, true, parent, true);
}
else
{
DeleteReference(Server.DefaultRequestContext, parent, ReferenceTypeIds.HasNotifier, false, child, true);
}
}
private void UpdateOrganizesReference(NodeId parent, NodeId child, bool add)
{
if (add)
{
AddReference(Server.DefaultRequestContext, parent, ReferenceTypeIds.Organizes, false, child, true);
}
else
{
DeleteReference(Server.DefaultRequestContext, parent, ReferenceTypeIds.Organizes, false, child, true);
}
}
private void UpdateParentChildReference(NodeId parent, NodeId child, bool add)
{
if (add)
{
AddReference(Server.DefaultRequestContext, parent, ReferenceTypeIds.HasChild, false, child, true);
}
else
{
DeleteReference(Server.DefaultRequestContext, parent, ReferenceTypeIds.HasChild, false, child, true);
}
}
private int m_i = 0;
private void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
var df = new DeviceFailureEventModel
{
SourceNode = sharedId,
SourceName = "ObjShared",
//EventId = Guid.NewGuid().ToByteArray(), //UNCOMMENTING THIS LINE OF CODE RESOLVES THE ISSUE.
Message = $"Event {++m_i}",
};
var ge = df.CreateEvent(Server.FilterManager);
ReportEvent(sharedId, ge);
}
public override void Shutdown()
{
base.Shutdown();
_timer.Enabled = false;
}
}
}
from ua expert you then monitor the EventRoot folder. Events will be received 3x
The reason i was not providing an eventId is because i thought that it would be automatically assigned by the sdk if i left it null but probably that only works if you call the Initialze method on the GenericEvent object as is explained in the documentation here:
http://documentation.unified-automation ... ess05.html
It would be nice if the codepath i used above also provided an eventId value in the case where the user does not specify one.