From 1a3e97afec65b7aae01616cef0378f95b4193a0e Mon Sep 17 00:00:00 2001 From: Christian <6939810+chkr1011@users.noreply.github.com> Date: Sun, 7 Dec 2025 16:24:34 +0100 Subject: [PATCH] Add support for dotnet 10 (#2229) * Add dotnet10 as target framework and fix breaking changes * Fix tests * Fix tests for CI * Fix typo --- .github/workflows/ci.yml | 4 +++- Directory.Build.props | 7 ++----- Samples/Server/Server_TLS_Samples.cs | 2 ++ .../Internal/Adapter/MqttTcpServerListener.cs | 5 +++++ Source/MQTTnet.TestApp/MQTTnet.TestApp.csproj | 1 - Source/MQTTnet.Tests/MQTTnet.Tests.csproj | 1 - Source/MQTTnet.Tests/Server/HotSwapCerts_Tests.cs | 2 ++ Source/MQTTnet.Tests/Server/Load_Tests.cs | 5 +++-- .../Server/Subscription_TopicHash_Tests.cs | 3 ++- Source/MQTTnet.Tests/Server/Tls_Tests.cs | 2 ++ .../MQTTnet/Certificates/BlobCertificateProvider.cs | 13 +++++++++++++ Source/ReleaseNotes.md | 1 + 12 files changed, 35 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 62c3a43d..030f1186 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,7 @@ jobs: with: dotnet-version: | 8.0.x + 10.0.x - name: Checkout code uses: actions/checkout@v4 @@ -48,12 +49,13 @@ jobs: with: dotnet-version: | 8.0.x + 10.0.x - name: Checkout code uses: actions/checkout@v4 - name: Execute tests - run: dotnet test --framework net8.0 --configuration Release Source/MQTTnet.Tests/MQTTnet.Tests.csproj + run: dotnet test --framework net10.0 --configuration Release Source/MQTTnet.Tests/MQTTnet.Tests.csproj sign: needs: build diff --git a/Directory.Build.props b/Directory.Build.props index c6146e2b..cc695f65 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - net8.0 + net8.0;net10.0 MQTTnet The contributors of MQTTnet The contributors of MQTTnet @@ -11,6 +11,7 @@ true false enable + disable en-US true @@ -24,10 +25,6 @@ latest recommended default - - true - true - true diff --git a/Samples/Server/Server_TLS_Samples.cs b/Samples/Server/Server_TLS_Samples.cs index ff859ea3..4e02cf34 100644 --- a/Samples/Server/Server_TLS_Samples.cs +++ b/Samples/Server/Server_TLS_Samples.cs @@ -59,10 +59,12 @@ public static class Server_TLS_Samples certRequest.CertificateExtensions.Add(sanBuilder.Build()); using var certificate = certRequest.CreateSelfSigned(DateTimeOffset.Now.AddMinutes(-10), DateTimeOffset.Now.AddMinutes(10)); +#pragma warning disable SYSLIB0057 var pfxCertificate = new X509Certificate2( certificate.Export(X509ContentType.Pfx), (string)null!, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable); +#pragma warning restore SYSLIB0057 return pfxCertificate; } diff --git a/Source/MQTTnet.Server/Internal/Adapter/MqttTcpServerListener.cs b/Source/MQTTnet.Server/Internal/Adapter/MqttTcpServerListener.cs index 6d71f742..a82ecdeb 100644 --- a/Source/MQTTnet.Server/Internal/Adapter/MqttTcpServerListener.cs +++ b/Source/MQTTnet.Server/Internal/Adapter/MqttTcpServerListener.cs @@ -202,9 +202,14 @@ public sealed class MqttTcpServerListener : IDisposable clientCertificate = sslStream.RemoteCertificate as X509Certificate2; + // TODO: Check why this export is needed. Is there something else in the RemoteCertificate as a X509Certificate2??? if (clientCertificate == null && sslStream.RemoteCertificate != null) { + #if NET10_0_OR_GREATER + clientCertificate = X509CertificateLoader.LoadCertificate(sslStream.RemoteCertificate.Export(X509ContentType.Cert)); + #else clientCertificate = new X509Certificate2(sslStream.RemoteCertificate.Export(X509ContentType.Cert)); + #endif } } diff --git a/Source/MQTTnet.TestApp/MQTTnet.TestApp.csproj b/Source/MQTTnet.TestApp/MQTTnet.TestApp.csproj index a4227da0..eed8f8c7 100644 --- a/Source/MQTTnet.TestApp/MQTTnet.TestApp.csproj +++ b/Source/MQTTnet.TestApp/MQTTnet.TestApp.csproj @@ -2,7 +2,6 @@ Exe - Full false diff --git a/Source/MQTTnet.Tests/MQTTnet.Tests.csproj b/Source/MQTTnet.Tests/MQTTnet.Tests.csproj index 84542954..7183f0ce 100644 --- a/Source/MQTTnet.Tests/MQTTnet.Tests.csproj +++ b/Source/MQTTnet.Tests/MQTTnet.Tests.csproj @@ -1,7 +1,6 @@ - Exe false default diff --git a/Source/MQTTnet.Tests/Server/HotSwapCerts_Tests.cs b/Source/MQTTnet.Tests/Server/HotSwapCerts_Tests.cs index 4b42fb88..8771b55d 100644 --- a/Source/MQTTnet.Tests/Server/HotSwapCerts_Tests.cs +++ b/Source/MQTTnet.Tests/Server/HotSwapCerts_Tests.cs @@ -122,10 +122,12 @@ public sealed class HotSwapCerts_Tests certRequest.CertificateExtensions.Add(sanBuilder.Build()); using var certificate = certRequest.CreateSelfSigned(DateTimeOffset.Now.AddMinutes(-10), DateTimeOffset.Now.AddMinutes(10)); +#pragma warning disable SYSLIB0057 var pfxCertificate = new X509Certificate2( certificate.Export(X509ContentType.Pfx), (string)null, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable); +#pragma warning restore SYSLIB0057 return pfxCertificate; } diff --git a/Source/MQTTnet.Tests/Server/Load_Tests.cs b/Source/MQTTnet.Tests/Server/Load_Tests.cs index 7573e50e..75490860 100644 --- a/Source/MQTTnet.Tests/Server/Load_Tests.cs +++ b/Source/MQTTnet.Tests/Server/Load_Tests.cs @@ -1,5 +1,6 @@ #if DEBUG +using System.Globalization; using MQTTnet.Internal; using MQTTnet.Packets; using MQTTnet.Protocol; @@ -52,7 +53,7 @@ public sealed class Load_Tests : BaseTestClass for (var j = 0; j < 1000; j++) { - publishPacket.Topic = j.ToString(); + publishPacket.Topic = j.ToString(CultureInfo.InvariantCulture); await client.SendAsync(publishPacket, CancellationToken.None); } @@ -139,7 +140,7 @@ public sealed class Load_Tests : BaseTestClass for (var j = 0; j < 1000; j++) { - var message = applicationMessageBuilder.WithTopic(j.ToString()).Build(); + var message = applicationMessageBuilder.WithTopic(j.ToString(CultureInfo.InvariantCulture)).Build(); await client.PublishAsync(message); } diff --git a/Source/MQTTnet.Tests/Server/Subscription_TopicHash_Tests.cs b/Source/MQTTnet.Tests/Server/Subscription_TopicHash_Tests.cs index 604b6d4b..905bc7fa 100644 --- a/Source/MQTTnet.Tests/Server/Subscription_TopicHash_Tests.cs +++ b/Source/MQTTnet.Tests/Server/Subscription_TopicHash_Tests.cs @@ -520,10 +520,11 @@ public sealed class SubscriptionTopicHashTests : IDisposable static byte[] GetBytes(ulong value) { var bytes = BitConverter.GetBytes(value); + // Ensure that highest byte comes first for comparison left to right if (BitConverter.IsLittleEndian) { - return bytes.Reverse().ToArray(); + bytes = bytes.AsEnumerable().Reverse().ToArray(); } return bytes; diff --git a/Source/MQTTnet.Tests/Server/Tls_Tests.cs b/Source/MQTTnet.Tests/Server/Tls_Tests.cs index 35b0bc49..e6d10334 100644 --- a/Source/MQTTnet.Tests/Server/Tls_Tests.cs +++ b/Source/MQTTnet.Tests/Server/Tls_Tests.cs @@ -31,10 +31,12 @@ public sealed class Tls_Tests : BaseTestClass certRequest.CertificateExtensions.Add(sanBuilder.Build()); using var certificate = certRequest.CreateSelfSigned(DateTimeOffset.Now.AddMinutes(-10), DateTimeOffset.Now.AddMinutes(10)); +#pragma warning disable SYSLIB0057 var pfxCertificate = new X509Certificate2( certificate.Export(X509ContentType.Pfx), (string)null, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable); +#pragma warning restore SYSLIB0057 return pfxCertificate; } diff --git a/Source/MQTTnet/Certificates/BlobCertificateProvider.cs b/Source/MQTTnet/Certificates/BlobCertificateProvider.cs index c8c149f9..29b7d15f 100644 --- a/Source/MQTTnet/Certificates/BlobCertificateProvider.cs +++ b/Source/MQTTnet/Certificates/BlobCertificateProvider.cs @@ -14,6 +14,17 @@ public class BlobCertificateProvider(byte[] blob) : ICertificateProvider public X509Certificate2 GetCertificate() { + #if NET10_0_OR_GREATER + + if (string.IsNullOrEmpty(Password)) + { + return X509CertificateLoader.LoadCertificate(Blob); + } + + return X509CertificateLoader.LoadPkcs12(Blob, Password); + + #else + if (string.IsNullOrEmpty(Password)) { // Use a different overload when no password is specified. Otherwise, the constructor will fail. @@ -21,5 +32,7 @@ public class BlobCertificateProvider(byte[] blob) : ICertificateProvider } return new X509Certificate2(Blob, Password); + + #endif } } \ No newline at end of file diff --git a/Source/ReleaseNotes.md b/Source/ReleaseNotes.md index c539dbe6..42cf8af4 100644 --- a/Source/ReleaseNotes.md +++ b/Source/ReleaseNotes.md @@ -7,3 +7,4 @@ * Marked all projects as AOT compatible * Restored the strong name of the nugets * Embedded license file in all nugets (#2197, thanks to @JensNordenbro) +* Added support for dotnet10