Session.Load doesn't create the monitored items. Opt-in to support load for subscription transfer. (#2113)

- Added a flag to the Session.Load function to indicate that a session transfer should be supported. Otherwise the serverId is reset after load, to support that the subscription is recreated on the server after load. 
- A user has to opt-in to get the transfer session support.
This commit is contained in:
Martin Regen
2023-04-11 08:45:34 +02:00
committed by GitHub
parent b5d4dd79cf
commit 620e7c42eb
3 changed files with 51 additions and 19 deletions
+4 -2
View File
@@ -296,15 +296,17 @@ namespace Opc.Ua.Client
/// Load the list of subscriptions saved in a file.
/// </summary>
/// <param name="stream">The stream.</param>
/// <param name="transferSubscriptions">Load the subscriptions for transfer after load.</param>
/// <returns>The list of loaded subscriptions</returns>
IEnumerable<Subscription> Load(Stream stream);
IEnumerable<Subscription> Load(Stream stream, bool transferSubscriptions = false);
/// <summary>
/// Load the list of subscriptions saved in a file.
/// </summary>
/// <param name="filePath">The file path.</param>
/// <param name="transferSubscriptions">Load the subscriptions for transfer after load.</param>
/// <returns>The list of loaded subscriptions</returns>
IEnumerable<Subscription> Load(string filePath);
IEnumerable<Subscription> Load(string filePath, bool transferSubscriptions = false);
/// <summary>
/// Updates the local copy of the server's namespace uri and server uri tables.
+14 -3
View File
@@ -1412,8 +1412,9 @@ namespace Opc.Ua.Client
/// Load the list of subscriptions saved in a stream.
/// </summary>
/// <param name="stream">The stream.</param>
/// <param name="transferSubscriptions">Load the subscriptions for transfer after load.</param>
/// <returns>The list of loaded subscriptions</returns>
public IEnumerable<Subscription> Load(Stream stream)
public IEnumerable<Subscription> Load(Stream stream, bool transferSubscriptions = false)
{
// secure settings
XmlReaderSettings settings = Utils.DefaultXmlReaderSettings();
@@ -1425,6 +1426,15 @@ namespace Opc.Ua.Client
SubscriptionCollection subscriptions = (SubscriptionCollection)serializer.ReadObject(reader);
foreach (Subscription subscription in subscriptions)
{
if (!transferSubscriptions)
{
// ServerId must be reset if the saved list of subscriptions
// is not used to transfer a subscription
foreach (var monitoredItem in subscription.MonitoredItems)
{
monitoredItem.ServerId = 0;
}
}
AddSubscription(subscription);
}
return subscriptions;
@@ -1435,12 +1445,13 @@ namespace Opc.Ua.Client
/// Load the list of subscriptions saved in a file.
/// </summary>
/// <param name="filePath">The file path.</param>
/// <param name="transferSubscriptions">Load the subscriptions for transfer after load.</param>
/// <returns>The list of loaded subscriptions</returns>
public IEnumerable<Subscription> Load(string filePath)
public IEnumerable<Subscription> Load(string filePath, bool transferSubscriptions = false)
{
using (FileStream stream = File.OpenRead(filePath))
{
return Load(stream);
return Load(stream, transferSubscriptions);
}
}
+33 -14
View File
@@ -35,7 +35,6 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using Opc.Ua.Server.Tests;
namespace Opc.Ua.Client.Tests
{
@@ -131,15 +130,18 @@ namespace Opc.Ua.Client.Tests
new MonitoredItem(subscription.DefaultItem)
{
DisplayName = "ServerStatusState", StartNodeId = VariableIds.Server_ServerStatus_State
}
},
};
var simulatedNodes = GetTestSetSimulation(Session.NamespaceUris);
list2.AddRange(CreateMonitoredItemTestSet(subscription, simulatedNodes));
list2.ForEach(i => i.Notification += (MonitoredItem item, MonitoredItemNotificationEventArgs e) => {
foreach (var value in item.DequeueValues())
{
TestContext.Out.WriteLine("{0}: {1}, {2}, {3}", item.DisplayName, value.Value, value.SourceTimestamp, value.StatusCode);
}
});
subscription.AddItems(list);
subscription.AddItems(list2);
subscription.ApplyChanges();
subscription.SetPublishingMode(false);
Assert.False(subscription.PublishingEnabled);
@@ -221,15 +223,18 @@ namespace Opc.Ua.Client.Tests
new MonitoredItem(subscription.DefaultItem)
{
DisplayName = "ServerStatusState", StartNodeId = VariableIds.Server_ServerStatus_State
}
},
};
var simulatedNodes = GetTestSetSimulation(Session.NamespaceUris);
list2.AddRange(CreateMonitoredItemTestSet(subscription, simulatedNodes));
list2.ForEach(i => i.Notification += (MonitoredItem item, MonitoredItemNotificationEventArgs e) => {
foreach (var value in item.DequeueValues())
{
TestContext.Out.WriteLine("{0}: {1}, {2}, {3}", item.DisplayName, value.Value, value.SourceTimestamp, value.StatusCode);
}
});
subscription.AddItems(list);
subscription.AddItems(list2);
await subscription.ApplyChangesAsync().ConfigureAwait(false);
await subscription.SetPublishingModeAsync(false).ConfigureAwait(false);
Assert.False(subscription.PublishingEnabled);
@@ -261,7 +266,7 @@ namespace Opc.Ua.Client.Tests
[Test, Order(200)]
public void LoadSubscription()
public async Task LoadSubscriptionAsync()
{
if (!File.Exists(m_subscriptionTestXml)) Assert.Ignore("Save file {0} does not exist yet", m_subscriptionTestXml);
@@ -270,22 +275,36 @@ namespace Opc.Ua.Client.Tests
Assert.NotNull(subscriptions);
Assert.IsNotEmpty(subscriptions);
int valueChanges = 0;
foreach (var subscription in subscriptions)
{
var list = subscription.MonitoredItems.ToList();
list.ForEach(i => i.Notification += (MonitoredItem item, MonitoredItemNotificationEventArgs e) => {
foreach (var value in item.DequeueValues())
{
valueChanges++;
TestContext.Out.WriteLine("{0}: {1}, {2}, {3}", item.DisplayName, value.Value, value.SourceTimestamp, value.StatusCode);
}
});
Session.AddSubscription(subscription);
subscription.Create();
await subscription.CreateAsync().ConfigureAwait(false);
}
Thread.Sleep(5000);
await Task.Delay(5000);
foreach (var subscription in subscriptions)
TestContext.Out.WriteLine("{0} value changes.", valueChanges);
Assert.GreaterOrEqual(valueChanges, 10);
foreach (var subscription in Session.Subscriptions)
{
OutputSubscriptionInfo(TestContext.Out, subscription);
}
var result = Session.RemoveSubscriptions(subscriptions);
var result = await Session.RemoveSubscriptionsAsync(subscriptions).ConfigureAwait(false);
Assert.True(result);
}
[Theory, Order(300)]
@@ -477,7 +496,7 @@ namespace Opc.Ua.Client.Tests
/// <summary>
/// The origin session gets network disconnected,
/// after transfer available sequence numbers are
/// just ackoledged.
/// just acknoledged.
/// </summary>
DisconnectedAck,
/// <summary>
@@ -586,8 +605,8 @@ namespace Opc.Ua.Client.Tests
var transferSubscriptions = new SubscriptionCollection();
if (transferType != TransferType.KeepOpen)
{
// load
transferSubscriptions.AddRange(targetSession.Load(filePath));
// load subscriptions for transfer
transferSubscriptions.AddRange(targetSession.Load(filePath, true));
// hook notifications for log output
int ii = 0;