chore(build): OpcUaClient driver/browser on ITelemetryContext ctors, TreatWarningsAsErrors on remaining src projects (#621 #606)

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-08 06:59:25 -04:00
parent 9b159025f7
commit b007d450d8
10 changed files with 40 additions and 22 deletions
@@ -4,6 +4,7 @@
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>ZB.MOM.WW.OtOpcUa.Client.CLI</RootNamespace>
</PropertyGroup>
@@ -237,10 +237,8 @@ public sealed class OpcUaClientService : IOpcUaClientService
hasChildren));
}
if (continuationPoint != null && continuationPoint.Length > 0)
(continuationPoint, references) = await _session.BrowseNextAsync(continuationPoint, ct);
else
break;
if (continuationPoint is not { Length: > 0 } pending) break;
(continuationPoint, references) = await _session.BrowseNextAsync(pending, ct);
}
return results;
@@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>ZB.MOM.WW.OtOpcUa.Client.Shared</RootNamespace>
</PropertyGroup>
@@ -4,6 +4,7 @@
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>ZB.MOM.WW.OtOpcUa.Client.UI</RootNamespace>
</PropertyGroup>
@@ -124,17 +124,13 @@ public sealed class OpcUaClientDriverBrowser : IDriverBrowser
/// <param name="ct">Cancellation token for the configuration build.</param>
private static async Task<ApplicationConfiguration> BuildBrowseAppConfigurationAsync(CancellationToken ct)
{
// The default ctor is obsolete in favour of the ITelemetryContext overload; suppress
// locally rather than plumbing a telemetry context all the way through — the browser
// emits no per-request telemetry of its own and the SDK's internal fallback is fine
// for a transient picker session (mirrors the runtime driver's same suppression).
#pragma warning disable CS0618
var app = new ApplicationInstance
// The ITelemetryContext overload is the non-obsolete ctor; an empty builder keeps SDK
// internals off any logging provider.
var app = new ApplicationInstance(BrowseTelemetry.Context)
{
ApplicationName = "OtOpcUa AdminUI Browse",
ApplicationType = ApplicationType.Client,
};
#pragma warning restore CS0618
var pkiRoot = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
@@ -245,3 +241,11 @@ public sealed class OpcUaClientDriverBrowser : IDriverBrowser
private static string ShortName(string uri) =>
uri?.Substring(uri.LastIndexOf('#') + 1) ?? "(null)";
}
internal static class BrowseTelemetry
{
private static readonly Lazy<Opc.Ua.ITelemetryContext> Instance = new(() => Opc.Ua.DefaultTelemetry.Create(_ => { }));
/// <summary>Gets the shared telemetry context.</summary>
public static Opc.Ua.ITelemetryContext Context => Instance.Value;
}
@@ -294,17 +294,13 @@ public sealed class OpcUaClientDriver : IDriver, ITagDiscovery, IReadable, IWrit
/// </summary>
private async Task<ApplicationConfiguration> BuildApplicationConfigurationAsync(CancellationToken ct)
{
// The default ctor is obsolete in favour of the ITelemetryContext overload; suppress
// locally rather than plumbing a telemetry context all the way through the driver
// surface — the driver emits no per-request telemetry of its own and the SDK's
// internal fallback is fine for a gateway use case.
#pragma warning disable CS0618
var app = new ApplicationInstance
// The ITelemetryContext overload is the non-obsolete ctor; an empty builder keeps SDK
// internals off any logging provider (mirrors Client.Shared's ClientTelemetry).
var app = new ApplicationInstance(SdkTelemetry.Context)
{
ApplicationName = _options.SessionName,
ApplicationType = ApplicationType.Client,
};
#pragma warning restore CS0618
var pkiRoot = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
@@ -472,7 +468,7 @@ public sealed class OpcUaClientDriver : IDriver, ITagDiscovery, IReadable, IWrit
endpointConfig.OperationTimeout = (int)_options.Timeout.TotalMilliseconds;
var endpoint = new ConfiguredEndpoint(null, selected, endpointConfig);
var session = await new DefaultSessionFactory(telemetry: null!).CreateAsync(
var session = await new DefaultSessionFactory(SdkTelemetry.Context).CreateAsync(
appConfig,
endpoint,
false, // updateBeforeConnect
@@ -0,0 +1,16 @@
using Opc.Ua;
namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient;
/// <summary>
/// The one <see cref="ITelemetryContext" /> the driver hands the SDK's non-obsolete (telemetry-taking)
/// overloads. An empty builder keeps SDK internals off any logging provider (mirrors Client.Shared's
/// <c>ClientTelemetry</c>).
/// </summary>
internal static class SdkTelemetry
{
private static readonly Lazy<ITelemetryContext> Instance = new(() => DefaultTelemetry.Create(_ => { }));
/// <summary>Gets the shared telemetry context.</summary>
public static ITelemetryContext Context => Instance.Value;
}
@@ -5,6 +5,7 @@
(which on .NET Framework 4.7.2 and .NET 6+ equally resolves netstandard2.0). -->
<TargetFramework>netstandard2.0</TargetFramework>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<LangVersion>latest</LangVersion>
<IsPackable>false</IsPackable>
<IsRoslynComponent>true</IsRoslynComponent>
@@ -37,7 +37,7 @@ public sealed class OpcUaClientContinuationPointReleaseTests
private static Mock<ISession> BuildCancellingSessionMock()
{
var mock = new Mock<ISession>(MockBehavior.Loose);
mock.SetupGet(s => s.MessageContext).Returns(new ServiceMessageContext());
mock.SetupGet(s => s.MessageContext).Returns(new ServiceMessageContext(ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.SdkTelemetry.Context));
mock.SetupGet(s => s.NamespaceUris).Returns(new NamespaceTable());
// BrowseAsync — return one Object child plus a non-empty continuation point so
@@ -148,7 +148,7 @@ public sealed class OpcUaClientContinuationPointReleaseTests
using var drv = new OpcUaClientDriver(new OpcUaClientDriverOptions(), "opcua-cp-norelease");
var mock = new Mock<ISession>(MockBehavior.Loose);
mock.SetupGet(s => s.MessageContext).Returns(new ServiceMessageContext());
mock.SetupGet(s => s.MessageContext).Returns(new ServiceMessageContext(ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.SdkTelemetry.Context));
mock.SetupGet(s => s.NamespaceUris).Returns(new NamespaceTable());
// BrowseAsync — return a result with a continuation point so the loop is entered.
@@ -53,7 +53,7 @@ public sealed class OpcUaClientStaleSessionRaceTests
// MessageContext. This getter is read in the driver's synchronous prologue (before the
// gate), so signalling here proves the pre-gate capture path has run.
mock.SetupGet(s => s.MessageContext)
.Returns(new ServiceMessageContext())
.Returns(new ServiceMessageContext(ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.SdkTelemetry.Context))
.Callback(() => prologueReached?.TrySetResult());
mock.SetupGet(s => s.NamespaceUris).Returns(new NamespaceTable());
mock.Setup(s => s.HistoryReadAsync(