Skip to content

Commit 6c8c1a6

Browse files
authored
Enable dispose analyzers CA2000 and CA2213 and fix all issues (#3670)
1 parent d188383 commit 6c8c1a6

213 files changed

Lines changed: 4560 additions & 4096 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.editorconfig

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,17 @@ dotnet_diagnostic.CA1511.severity =
384384
dotnet_diagnostic.CA1512.severity = none
385385
dotnet_diagnostic.CA1513.severity = none
386386

387+
# CA2213: Disposable fields should be disposed
388+
dotnet_diagnostic.CA2213.severity = error
389+
# CA2000: Dispose objects before losing scope
390+
dotnet_diagnostic.CA2000.severity = error
391+
# CA1001: Types that own disposable fields should be disposable
392+
dotnet_diagnostic.CA1001.severity = warning
393+
# CA1849: Call async methods when in an async method
394+
dotnet_diagnostic.CA1849.severity = suggestion
395+
# CA2225: Operator overloads have named alternates
396+
dotnet_diagnostic.CA2225.severity = suggestion
397+
387398
#
388399
# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/language-rules
389400
#
@@ -409,6 +420,8 @@ dotnet_diagnostic.IDE1005.severity =
409420
dotnet_diagnostic.IDE0046.severity = silent
410421
# IDE0130: Namespace does not match folder structure
411422
dotnet_diagnostic.IDE0130.severity = none
423+
# IDE0032: Use auto property
424+
dotnet_diagnostic.IDE0032.severity = suggestion
412425

413426
#
414427
# Introduced in .net 10 as part of all analysis configuration
@@ -433,23 +446,8 @@ dotnet_diagnostic.CA1716.severity =
433446
# CA1724: The type conflicts in whole or in part with a namespace name
434447
dotnet_diagnostic.CA1724.severity = none
435448

436-
# TODO Fix as P1:
437-
438-
# CA2213: Disposable fields should be disposed
439-
dotnet_diagnostic.CA2213.severity = none
440-
# CA2000: Dispose objects before losing scope
441-
dotnet_diagnostic.CA2000.severity = none
442-
# CA1001: Types that own disposable fields should be disposable
443-
dotnet_diagnostic.CA1001.severity = none
444-
# IDE0032: Use auto property
445-
dotnet_diagnostic.IDE0032.severity = none
446-
# CA1849: Call async methods when in an async method
447-
dotnet_diagnostic.CA1849.severity = none
448-
449449
# TODO: Fix as P2:
450450

451-
# CA2225: Operator overloads have named alternates
452-
dotnet_diagnostic.CA2225.severity = none
453451
# CA1848: Use the LoggerMessage delegates
454452
dotnet_diagnostic.CA1848.severity = none
455453
# CA1873: Avoid potentially expensive logging

.github/workflows/buildandtest.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,10 @@ jobs:
123123
name: aot-results-${{ matrix.os }}
124124
path: '**/TestResults/**'
125125
if: ${{ always() }}
126+
127+
- name: Upload HTML Test Report
128+
uses: actions/upload-artifact@v7
129+
with:
130+
name: TestReport
131+
path: '**/*-report.html'
132+
if: ${{ always() }}

Applications/ConsoleReferenceClient/ClientSamples.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public interface IUAClient
6262
/// <summary>
6363
/// Sample Session calls based on the reference server node model.
6464
/// </summary>
65-
public partial class ClientSamples
65+
public class ClientSamples
6666
{
6767
private const int kMaxSearchDepth = 128;
6868

Applications/ConsoleReferenceClient/RunConnectAll.cs renamed to Applications/ConsoleReferenceClient/ConnectTester.cs

Lines changed: 66 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
* ======================================================================*/
2929

3030
using System;
31+
using System.Collections;
3132
using System.Collections.Generic;
3233
using System.IO;
3334
using System.Linq;
@@ -42,9 +43,33 @@
4243

4344
namespace Quickstarts
4445
{
45-
public partial class ClientSamples
46+
/// <summary>
47+
/// Wraps connect testing functionality
48+
/// </summary>
49+
public sealed class ConnectTester : IDisposable
4650
{
47-
public async Task<bool> RunAsync(ManualResetEvent quitEvent, CancellationToken ct)
51+
public ConnectTester(
52+
ITelemetryContext telemetry,
53+
ManualResetEvent quitEvent = null)
54+
{
55+
m_quitEvent = quitEvent;
56+
m_telemetry = telemetry;
57+
m_logger = telemetry.CreateLogger<ConnectTester>();
58+
}
59+
60+
/// <inheritdoc/>
61+
public void Dispose()
62+
{
63+
m_reconnectHandler?.Dispose();
64+
}
65+
66+
/// <summary>
67+
/// Run the tests until cancelled or quit
68+
/// </summary>
69+
/// <param name="ct"></param>
70+
/// <returns></returns>
71+
/// <exception cref="InvalidOperationException"></exception>
72+
public async Task RunAsync(CancellationToken ct)
4873
{
4974
try
5075
{
@@ -54,7 +79,6 @@ public async Task<bool> RunAsync(ManualResetEvent quitEvent, CancellationToken c
5479
kReconnectPeriodExponentialBackoff);
5580

5681
m_logger.LogInformation("OPC UA Security Test Client");
57-
CryptoTrace.Enabled = false;
5882

5983
// The application name and config file names
6084
const string applicationName = "ConsoleReferenceClient";
@@ -95,8 +119,6 @@ public async Task<bool> RunAsync(ManualResetEvent quitEvent, CancellationToken c
95119
kServerUrl,
96120
ct).ConfigureAwait(false);
97121

98-
//endpoints = endpoints.Where(x => x.SecurityPolicyUri == TargetPolicy).ToList();
99-
100122
var endpointConfiguration = EndpointConfiguration.Create(m_configuration);
101123
var sessionFactory = new DefaultSessionFactory(m_telemetry);
102124
var userNameidentity = new UserIdentity(kUserName, new UTF8Encoding(false).GetBytes(kPassword));
@@ -204,54 +226,17 @@ public async Task<bool> RunAsync(ManualResetEvent quitEvent, CancellationToken c
204226
ii.SecurityMode);
205227

206228
m_logger.LogWarning("{Line}", new string('=', 80));
207-
//break;
208229
}
209-
210-
//break;
211230
}
212231

213232
Console.WriteLine("Ctrl-C to stop.");
214-
quitEvent.WaitOne();
233+
m_quitEvent.WaitOne();
215234
}
216235
catch (Exception e)
217236
{
218237
m_logger.LogError("Exception: {Message}", e.Message);
219238
m_logger.LogTrace("StackTrace: {StackTrace}", e.StackTrace);
220239
}
221-
222-
return true;
223-
}
224-
225-
private async Task<UserIdentity> LoadUserCertificateAsync(
226-
string thumbprint,
227-
string password,
228-
CancellationToken ct)
229-
{
230-
CertificateTrustList store = m_configuration.SecurityConfiguration.TrustedUserCertificates;
231-
#if NET8_0_OR_GREATER
232-
// get user certificate with matching thumbprint
233-
X509Certificate2Collection certificates =
234-
await store.GetCertificatesAsync(m_telemetry, ct).ConfigureAwait(false);
235-
X509Certificate2 hit = certificates
236-
.Find(X509FindType.FindByThumbprint, thumbprint, false)
237-
.FirstOrDefault();
238-
239-
// create Certificate Identifier
240-
var cid = new CertificateIdentifier(hit)
241-
{
242-
StorePath = store.StorePath,
243-
StoreType = store.StoreType
244-
};
245-
246-
return await UserIdentity.CreateAsync(
247-
cid,
248-
new CertificatePasswordProvider(new UTF8Encoding(false).GetBytes(password)),
249-
m_telemetry,
250-
ct).ConfigureAwait(false);
251-
#else
252-
await Task.Delay(1, ct).ConfigureAwait(false);
253-
throw new NotSupportedException("User certificate identity is only supported on .NET 8 or greater.");
254-
#endif
255240
}
256241

257242
internal async Task<SessionWrapper> RunTestAsync(
@@ -293,7 +278,8 @@ internal async Task<SessionWrapper> RunTestAsync(
293278
wrapper.Session.KeepAliveInterval = 10000;
294279
wrapper.Session.KeepAlive += Session_KeepAlive;
295280

296-
ArrayOf<ReferenceDescription> nodes = await BrowseFullAddressSpaceAsync(
281+
var samples = new ClientSamples(m_telemetry, null, m_quitEvent);
282+
ArrayOf<ReferenceDescription> nodes = await samples.BrowseFullAddressSpaceAsync(
297283
wrapper,
298284
ObjectIds.ObjectsFolder,
299285
null,
@@ -302,6 +288,38 @@ internal async Task<SessionWrapper> RunTestAsync(
302288
return wrapper;
303289
}
304290

291+
private async Task<UserIdentity> LoadUserCertificateAsync(
292+
string thumbprint,
293+
string password,
294+
CancellationToken ct)
295+
{
296+
CertificateTrustList store = m_configuration.SecurityConfiguration.TrustedUserCertificates;
297+
#if NET8_0_OR_GREATER
298+
// get user certificate with matching thumbprint
299+
X509Certificate2Collection certificates =
300+
await store.GetCertificatesAsync(m_telemetry, ct).ConfigureAwait(false);
301+
X509Certificate2 hit = certificates
302+
.Find(X509FindType.FindByThumbprint, thumbprint, false)
303+
.FirstOrDefault();
304+
305+
// create Certificate Identifier
306+
var cid = new CertificateIdentifier(hit)
307+
{
308+
StorePath = store.StorePath,
309+
StoreType = store.StoreType
310+
};
311+
312+
return await UserIdentity.CreateAsync(
313+
cid,
314+
new CertificatePasswordProvider(new UTF8Encoding(false).GetBytes(password)),
315+
m_telemetry,
316+
ct).ConfigureAwait(false);
317+
#else
318+
await Task.Delay(1, ct).ConfigureAwait(false);
319+
throw new NotSupportedException("User certificate identity is only supported on .NET 8 or greater.");
320+
#endif
321+
}
322+
305323
private static async ValueTask<ArrayOf<EndpointDescription>> GetEndpointsAsync(
306324
ApplicationConfiguration application,
307325
string discoveryUrl,
@@ -425,7 +443,7 @@ private void Client_ReconnectComplete(object sender, EventArgs e)
425443
);
426444
ISession session = m_wrapper.Session;
427445
m_wrapper = new SessionWrapper { Session = m_reconnectHandler.Session };
428-
Utils.SilentDispose(session);
446+
session?.Dispose();
429447
}
430448
else
431449
{
@@ -469,6 +487,9 @@ internal sealed class SessionWrapper : IUAClient
469487
private SessionReconnectHandler m_reconnectHandler;
470488
private ApplicationConfiguration m_configuration;
471489
private SessionWrapper m_wrapper;
490+
private ILogger m_logger;
491+
private ITelemetryContext m_telemetry;
492+
private readonly ManualResetEvent m_quitEvent;
472493

473494
private const string kServerUrl = "opc.tcp://localhost:62541";
474495
private const string kUserName = "sysadmin";

Applications/ConsoleReferenceClient/Program.cs

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,6 @@ public static class Program
5555
/// Main entry point.
5656
/// </summary>
5757
/// <exception cref="ErrorExitException"></exception>
58-
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026",
59-
Justification = "NodeSet2 export uses XmlSerializer with known OPC UA types.")]
60-
[UnconditionalSuppressMessage("AOT", "IL3050",
61-
Justification = "NodeSet2 export uses XmlSerializer with known OPC UA types.")]
6258
public static Task<int> Main(string[] args)
6359
{
6460
Console.WriteLine("OPC UA Console Reference Client");
@@ -293,7 +289,7 @@ public static Task<int> Main(string[] args)
293289
logConsole,
294290
fileLog,
295291
appLog,
296-
LogLevel.Warning);
292+
LogLevel.Information);
297293

298294
// delete old certificate
299295
if (renewCertificate)
@@ -331,16 +327,11 @@ await application.DeleteApplicationInstanceCertificateAsync(ct: cancellationToke
331327
// handle connect all endpoints test.
332328
if (testallEndpoints)
333329
{
334-
var tester = new ClientSamples(
330+
var tester = new ConnectTester(
335331
telemetry,
336-
null,
337-
quitEvent,
338-
verbose);
339-
340-
if (await tester.RunAsync(quitEvent, ct).ConfigureAwait(false))
341-
{
342-
return;
343-
}
332+
quitEvent);
333+
await tester.RunAsync(ct).ConfigureAwait(false);
334+
return;
344335
}
345336

346337
var userIdentity = new UserIdentity();
@@ -742,7 +733,7 @@ await uaClient
742733
}
743734
finally
744735
{
745-
Utils.SilentDispose(reverseConnectManager);
736+
reverseConnectManager?.Dispose();
746737
}
747738
});
748739

Applications/ConsoleReferenceClient/UAClient.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ protected virtual void Dispose(bool disposing)
9393
}
9494
if (disposing)
9595
{
96-
Utils.SilentDispose(Session);
96+
m_reconnectHandler?.Dispose();
97+
Session?.Dispose();
9798
m_configuration.CertificateValidator.CertificateValidation -= CertificateValidation;
9899
}
99100
m_disposed = true;
@@ -437,7 +438,7 @@ private void Client_ReconnectComplete(object sender, EventArgs e)
437438
);
438439
ISession session = Session;
439440
Session = m_reconnectHandler.Session;
440-
Utils.SilentDispose(session);
441+
session?.Dispose();
441442
}
442443
else
443444
{

Applications/ConsoleReferenceServer/ConsoleUtils.cs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,16 @@ public ConsoleTelemetry(Action<ILoggingBuilder> configure = null)
6363
{
6464
builder.SetMinimumLevel(LogLevel.Information);
6565
m_configure?.Invoke(builder);
66-
})
67-
.AddSerilog(Log.Logger);
66+
});
67+
try
68+
{
69+
LoggerFactory = LoggerFactory.AddSerilog(Log.Logger);
70+
}
71+
catch
72+
{
73+
LoggerFactory.Dispose();
74+
throw;
75+
}
6876

6977
ActivitySource = new ActivitySource("Quickstarts", "1.0.0");
7078

@@ -186,15 +194,22 @@ public void ConfigureLogging(
186194
// create the serilog logger
187195
Serilog.Core.Logger serilogger = loggerConfiguration.CreateLogger();
188196

189-
// Dispose the old LoggerFactory and create a new one with the updated configuration
190197
ILoggerFactory oldLoggerFactory = LoggerFactory;
191198
LoggerFactory = Microsoft.Extensions.Logging.LoggerFactory
192199
.Create(builder =>
193200
{
194201
builder.SetMinimumLevel(consoleLogLevel);
195202
m_configure?.Invoke(builder);
196-
})
197-
.AddSerilog(serilogger);
203+
});
204+
try
205+
{
206+
LoggerFactory = LoggerFactory.AddSerilog(serilogger);
207+
}
208+
catch
209+
{
210+
LoggerFactory.Dispose();
211+
throw;
212+
}
198213
m_logger = LoggerFactory.CreateLogger("Main");
199214

200215
oldLoggerFactory.Dispose();

Applications/ConsoleReferenceServer/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ await server
179179
logConsole,
180180
fileLog,
181181
appLog,
182-
LogLevel.Warning);
182+
LogLevel.Information);
183183

184184
// check or renew the certificate
185185
Console.WriteLine("Check the certificate.");

0 commit comments

Comments
 (0)