diff --git a/Directory.Packages.props b/Directory.Packages.props
index 07591140..17b9745e 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -74,7 +74,7 @@
-
+
diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OpcUaApplicationHost.cs b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OpcUaApplicationHost.cs
index 5bd459dd..77ca866b 100644
--- a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OpcUaApplicationHost.cs
+++ b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OpcUaApplicationHost.cs
@@ -1,3 +1,4 @@
+using System.Text;
using Microsoft.Extensions.Logging;
using Opc.Ua;
using Opc.Ua.Configuration;
@@ -125,7 +126,10 @@ public sealed class OpcUaApplicationHost : IAsyncDisposable
public async Task StartAsync(StandardServer server, CancellationToken cancellationToken)
{
_server = server;
- _application = new ApplicationInstance
+ // 1.5.378 requires an ITelemetryContext on the ApplicationInstance ctor (the parameterless ctor
+ // is obsolete). DefaultTelemetry.Create wires the SDK's internal logging; an empty builder keeps
+ // the SDK's trace off our ILogger (the host keeps its own _logger) — sufficient for the bootstrap.
+ _application = new ApplicationInstance(DefaultTelemetry.Create(_ => { }))
{
ApplicationName = _options.ApplicationName,
ApplicationType = ApplicationType.Server,
@@ -134,7 +138,7 @@ public sealed class OpcUaApplicationHost : IAsyncDisposable
_ = await BuildConfigurationAsync(cancellationToken);
await EnsureApplicationCertificateAsync(cancellationToken).ConfigureAwait(false);
- await _application.Start(server).ConfigureAwait(false);
+ await _application.StartAsync(server).ConfigureAwait(false);
AttachUserAuthenticator();
PopulateServerArray();
@@ -223,7 +227,7 @@ public sealed class OpcUaApplicationHost : IAsyncDisposable
}
}
- private void OnImpersonateUser(Session session, ImpersonateEventArgs args) =>
+ private void OnImpersonateUser(ISession session, ImpersonateEventArgs args) =>
HandleImpersonation(_userAuthenticator, args, _logger);
///
@@ -248,7 +252,10 @@ public sealed class OpcUaApplicationHost : IAsyncDisposable
string password;
try
{
- password = token.DecryptedPassword ?? string.Empty;
+ // 1.5.378 exposes DecryptedPassword as raw bytes (was string); UserName token passwords
+ // are UTF-8 on the wire.
+ var decryptedBytes = token.DecryptedPassword;
+ password = decryptedBytes is null ? string.Empty : Encoding.UTF8.GetString(decryptedBytes);
}
catch (Exception ex)
{
@@ -299,8 +306,8 @@ public sealed class OpcUaApplicationHost : IAsyncDisposable
{
// silent: false → SDK logs cert creation events through its own trace plumbing.
// minimumKeySize/lifetimeInMonths: 0 → use SDK defaults (2048-bit, 12-month lifetime).
- var ok = await _application!.CheckApplicationInstanceCertificate(
- silent: false, minimumKeySize: 0, lifeTimeInMonths: 0, ct: cancellationToken).ConfigureAwait(false);
+ var ok = await _application!.CheckApplicationInstanceCertificatesAsync(
+ false, null, cancellationToken).ConfigureAwait(false);
if (!ok)
{
throw new InvalidOperationException(
@@ -313,7 +320,7 @@ public sealed class OpcUaApplicationHost : IAsyncDisposable
{
if (!string.IsNullOrWhiteSpace(_options.ApplicationConfigPath))
{
- return await _application!.LoadApplicationConfiguration(_options.ApplicationConfigPath, silent: true);
+ return await _application!.LoadApplicationConfigurationAsync(_options.ApplicationConfigPath, true, ct);
}
var serverConfig = new ServerConfiguration
@@ -358,7 +365,7 @@ public sealed class OpcUaApplicationHost : IAsyncDisposable
TraceConfiguration = new TraceConfiguration(),
};
- await config.Validate(ApplicationType.Server).ConfigureAwait(false);
+ await config.ValidateAsync(ApplicationType.Server, ct).ConfigureAwait(false);
_application!.ApplicationConfiguration = config;
return config;
}
@@ -430,7 +437,7 @@ public sealed class OpcUaApplicationHost : IAsyncDisposable
}
/// Disposes the application host and cleans up resources.
- public ValueTask DisposeAsync()
+ public async ValueTask DisposeAsync()
{
if (_impersonateHandler is not null && _server?.CurrentInstance?.SessionManager is { } sessionManager)
{
@@ -439,8 +446,11 @@ public sealed class OpcUaApplicationHost : IAsyncDisposable
}
_impersonateHandler = null;
- try { _application?.Stop(); }
- catch (Exception ex) { _logger.LogWarning(ex, "OpcUaApplicationHost: Stop threw on dispose"); }
- return ValueTask.CompletedTask;
+ if (_application is not null)
+ {
+ // 1.5.378: ApplicationInstance.Stop() → StopAsync().
+ try { await _application.StopAsync().ConfigureAwait(false); }
+ catch (Exception ex) { _logger.LogWarning(ex, "OpcUaApplicationHost: Stop threw on dispose"); }
+ }
}
}
diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/ZB.MOM.WW.OtOpcUa.OpcUaServer.csproj b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/ZB.MOM.WW.OtOpcUa.OpcUaServer.csproj
index c94c0b29..54dae8ad 100644
--- a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/ZB.MOM.WW.OtOpcUa.OpcUaServer.csproj
+++ b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/ZB.MOM.WW.OtOpcUa.OpcUaServer.csproj
@@ -7,11 +7,12 @@
-
-
+
+
diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/DualEndpointTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/DualEndpointTests.cs
index 5b529eb0..8de20862 100644
--- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/DualEndpointTests.cs
+++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/DualEndpointTests.cs
@@ -7,7 +7,6 @@ using Opc.Ua.Server;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.OpcUaServer;
-using ClientSession = Opc.Ua.Client.Session;
namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests;
@@ -85,23 +84,27 @@ public sealed class DualEndpointTests
},
ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60_000 },
};
- await appConfig.Validate(ApplicationType.Client);
+ await appConfig.ValidateAsync(ApplicationType.Client, default);
appConfig.CertificateValidator.CertificateValidation += (_, e) => e.Accept = true;
- var endpoint = CoreClientUtils.SelectEndpoint(appConfig, endpointUrl, useSecurity: false);
+ // 1.5.378: the discovery/session/read client surface moved to async.
+ var endpoint = await CoreClientUtils.SelectEndpointAsync(
+ appConfig, endpointUrl, false, DefaultTelemetry.Create(_ => { }), default);
var endpointConfiguration = EndpointConfiguration.Create(appConfig);
var configuredEndpoint = new ConfiguredEndpoint(null, endpoint, endpointConfiguration);
- using var session = await ClientSession.Create(
+ using var session = await new DefaultSessionFactory(DefaultTelemetry.Create(_ => { })).CreateAsync(
appConfig,
configuredEndpoint,
updateBeforeConnect: false,
+ checkDomain: false,
sessionName: "DualEndpointTests",
sessionTimeout: 60_000,
identity: new UserIdentity(new AnonymousIdentityToken()),
- preferredLocales: null);
+ preferredLocales: null,
+ ct: default);
- var value = session.ReadValue(VariableIds.Server_ServerArray);
+ var value = await session.ReadValueAsync(VariableIds.Server_ServerArray, default);
return (string[])value.Value;
}
diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests.csproj b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests.csproj
index 3d51e7ad..4f154d1c 100644
--- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests.csproj
+++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests.csproj
@@ -11,12 +11,11 @@
-
-
-
+
+
+
all
diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/OpcUaApplicationHostImpersonationTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/OpcUaApplicationHostImpersonationTests.cs
index f44bf71d..a7bb5d9e 100644
--- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/OpcUaApplicationHostImpersonationTests.cs
+++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/OpcUaApplicationHostImpersonationTests.cs
@@ -1,3 +1,4 @@
+using System.Text;
using Microsoft.Extensions.Logging.Abstractions;
using Opc.Ua;
using Opc.Ua.Server;
@@ -21,7 +22,7 @@ public sealed class OpcUaApplicationHostImpersonationTests
[Fact]
public void HandleImpersonation_username_success_sets_identity_and_no_validation_error()
{
- var token = new UserNameIdentityToken { UserName = "alice", DecryptedPassword = "secret" };
+ var token = new UserNameIdentityToken { UserName = "alice", DecryptedPassword = Encoding.UTF8.GetBytes("secret") };
var args = new ImpersonateEventArgs(token, UserNamePolicy, new EndpointDescription());
var authenticator = new RecordingAuthenticator(
OpcUaUserAuthResult.Allow("Alice", new[] { "ReadOnly", "WriteOperate" }));
@@ -38,7 +39,7 @@ public sealed class OpcUaApplicationHostImpersonationTests
[Fact]
public void HandleImpersonation_username_denial_sets_validation_error_and_no_identity()
{
- var token = new UserNameIdentityToken { UserName = "mallory", DecryptedPassword = "wrong" };
+ var token = new UserNameIdentityToken { UserName = "mallory", DecryptedPassword = Encoding.UTF8.GetBytes("wrong") };
var args = new ImpersonateEventArgs(token, UserNamePolicy, new EndpointDescription());
var authenticator = new RecordingAuthenticator(OpcUaUserAuthResult.Deny("Invalid credentials"));
@@ -68,7 +69,7 @@ public sealed class OpcUaApplicationHostImpersonationTests
[Fact]
public void HandleImpersonation_authenticator_throwing_results_in_rejection()
{
- var token = new UserNameIdentityToken { UserName = "bob", DecryptedPassword = "x" };
+ var token = new UserNameIdentityToken { UserName = "bob", DecryptedPassword = Encoding.UTF8.GetBytes("x") };
var args = new ImpersonateEventArgs(token, UserNamePolicy, new EndpointDescription());
var authenticator = new ThrowingAuthenticator(new InvalidOperationException("LDAP unreachable"));
@@ -82,7 +83,7 @@ public sealed class OpcUaApplicationHostImpersonationTests
[Fact]
public void HandleImpersonation_null_username_treated_as_empty_string()
{
- var token = new UserNameIdentityToken { UserName = null, DecryptedPassword = "abc" };
+ var token = new UserNameIdentityToken { UserName = null, DecryptedPassword = Encoding.UTF8.GetBytes("abc") };
var args = new ImpersonateEventArgs(token, UserNamePolicy, new EndpointDescription());
var authenticator = new RecordingAuthenticator(OpcUaUserAuthResult.Deny("no user"));