diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 0dfbccc4e..3804712a3 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "nuke.globaltool": { - "version": "6.0.3", + "version": "10.1.0", "commands": [ "nuke" ] diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json index b96a92417..90081562c 100644 --- a/.nuke/build.schema.json +++ b/.nuke/build.schema.json @@ -1,23 +1,56 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/build", - "title": "Build Schema", "definitions": { - "build": { - "type": "object", + "Host": { + "type": "string", + "enum": [ + "AppVeyor", + "AzurePipelines", + "Bamboo", + "Bitbucket", + "Bitrise", + "GitHubActions", + "GitLab", + "Jenkins", + "Rider", + "SpaceAutomation", + "TeamCity", + "Terminal", + "TravisCI", + "VisualStudio", + "VSCode" + ] + }, + "ExecutableTarget": { + "type": "string", + "enum": [ + "Clean", + "Compile", + "CompileDotNet", + "CompileNetFramework", + "CopyToLocalPackages", + "Default", + "Pack", + "PackTestPortForwarder", + "Restore", + "TestLinux", + "TestWindows", + "TestWindowsDotNet", + "TestWindowsNetFramework" + ] + }, + "Verbosity": { + "type": "string", + "description": "", + "enum": [ + "Verbose", + "Normal", + "Minimal", + "Quiet" + ] + }, + "NukeBuild": { "properties": { - "AutoDetectBranch": { - "type": "boolean", - "description": "Whether to auto-detect the branch name - this is okay for a local build, but should not be used under CI" - }, - "Configuration": { - "type": "string", - "description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)", - "enum": [ - "Debug", - "Release" - ] - }, "Continue": { "type": "boolean", "description": "Indicates to continue a previously failed build attempt" @@ -27,34 +60,13 @@ "description": "Shows the help text for this build assembly" }, "Host": { - "type": "string", "description": "Host for execution. Default is 'automatic'", - "enum": [ - "AppVeyor", - "AzurePipelines", - "Bamboo", - "Bitbucket", - "Bitrise", - "GitHubActions", - "GitLab", - "Jenkins", - "Rider", - "SpaceAutomation", - "TeamCity", - "Terminal", - "TravisCI", - "VisualStudio", - "VSCode" - ] + "$ref": "#/definitions/Host" }, "NoLogo": { "type": "boolean", "description": "Disables displaying the NUKE logo" }, - "OCTOVERSION_CurrentBranch": { - "type": "string", - "description": "Branch name for OctoVersion to use to calculate the version number. Can be set via the environment variable OCTOVERSION_CurrentBranch" - }, "Partition": { "type": "string", "description": "Partition to use on CI" @@ -74,73 +86,65 @@ "type": "string", "description": "Root directory during build execution" }, - "RunDotMemoryTests": { - "type": "boolean", - "description": "True if dot memory tests should be run, otherwise false. Default to True for Windows and False for Linux" - }, "Skip": { "type": "array", "description": "List of targets to be skipped. Empty list skips all dependencies", "items": { - "type": "string", - "enum": [ - "Clean", - "Compile", - "CompileNet48", - "CompileNet80", - "CopyToLocalPackages", - "Default", - "Pack", - "PackTestPortForwarder", - "Restore", - "TestLinux", - "TestWindows", - "TestWindowsNet48", - "TestWindowsNet80" - ] + "$ref": "#/definitions/ExecutableTarget" } }, - "Solution": { - "type": "string", - "description": "Path to a solution file that is automatically loaded" - }, "Target": { "type": "array", "description": "List of targets to be invoked. Default is '{default_target}'", "items": { - "type": "string", - "enum": [ - "Clean", - "Compile", - "CompileNet48", - "CompileNet80", - "CopyToLocalPackages", - "Default", - "Pack", - "PackTestPortForwarder", - "Restore", - "TestLinux", - "TestWindows", - "TestWindowsNet48", - "TestWindowsNet80" - ] + "$ref": "#/definitions/ExecutableTarget" } }, - "TestFilter": { - "type": "string", - "description": "The test Filter passed to dotnet test e.g. TestCategory=Async" - }, "Verbosity": { - "type": "string", "description": "Logging verbosity during build execution. Default is 'Normal'", + "$ref": "#/definitions/Verbosity" + } + } + } + }, + "allOf": [ + { + "properties": { + "AutoDetectBranch": { + "type": "boolean", + "description": "Whether to auto-detect the branch name - this is okay for a local build, but should not be used under CI" + }, + "Configuration": { + "type": "string", + "description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)", "enum": [ - "Minimal", - "Normal", - "Quiet", - "Verbose" + "Debug", + "Release" ] + }, + "OCTOVERSION_CurrentBranch": { + "type": "string", + "description": "Branch name for OctoVersion to use to calculate the version number. Can be set via the environment variable OCTOVERSION_CurrentBranch" + }, + "RunDotMemoryTests": { + "type": [ + "boolean", + "null" + ], + "description": "True if dot memory tests should be run, otherwise false. Default to True for Windows and False for Linux" + }, + "Solution": { + "type": "string", + "description": "Path to a solution file that is automatically loaded" + }, + "TestFilter": { + "type": "string", + "description": "The test Filter passed to dotnet test e.g. TestCategory=Async" } } + }, + { + "$ref": "#/definitions/NukeBuild" } - } + ] } diff --git a/build/Build.cs b/build/Build.cs index 98bdb3599..dd0c3464f 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -10,7 +10,6 @@ using Nuke.Common.Tools.OctoVersion; using Nuke.Common.Utilities; using Nuke.Common.Utilities.Collections; -using static Nuke.Common.IO.FileSystemTasks; using static Nuke.Common.Tools.DotMemoryUnit.DotMemoryUnitTasks; using static Nuke.Common.Tools.DotNet.DotNetTasks; @@ -35,7 +34,7 @@ class Build : NukeBuild [Parameter("Branch name for OctoVersion to use to calculate the version number. Can be set via the environment variable OCTOVERSION_CurrentBranch.", Name = "OCTOVERSION_CurrentBranch")] readonly string BranchName; - [OctoVersion(UpdateBuildNumber = true, BranchMember = nameof(BranchName), AutoDetectBranchMember = nameof(AutoDetectBranch), Framework = "net8.0")] + [OctoVersion(UpdateBuildNumber = true, BranchMember = nameof(BranchName), AutoDetectBranchMember = nameof(AutoDetectBranch), Framework = "net10.0")] readonly OctoVersionInfo OctoVersionInfo; [Parameter("The test Filter passed to dotnet test e.g. TestCategory=Async")] @@ -79,9 +78,9 @@ class Build : NukeBuild Target Compile => _ => CompileDefinition(_, null); - Target CompileNet48 => _ => CompileDefinition(_, "net48"); + Target CompileNetFramework => _ => CompileDefinition(_, "net48"); - Target CompileNet80 => _ => CompileDefinition(_, "net8.0"); + Target CompileDotNet => _ => CompileDefinition(_, "net10.0"); ITargetDefinition CompileDefinition(ITargetDefinition targetDefinition, [CanBeNull] string framework) { @@ -106,10 +105,10 @@ ITargetDefinition CompileDefinition(ITargetDefinition targetDefinition, [CanBeNu Target TestLinux => _ => TestDefinition(_, Compile, null, runDotMemoryTests: false); [PublicAPI] - Target TestWindowsNet48 => _ => TestDefinition(_, CompileNet48, "net48", runDotMemoryTests: true); + Target TestWindowsNetFramework => _ => TestDefinition(_, CompileNetFramework, "net48", runDotMemoryTests: true); [PublicAPI] - Target TestWindowsNet80 => _ => TestDefinition(_, CompileNet80, "net8.0", runDotMemoryTests: false); + Target TestWindowsDotNet => _ => TestDefinition(_, CompileDotNet, "net10.0", runDotMemoryTests: false); ITargetDefinition TestDefinition(ITargetDefinition targetDefinition, Target dependsOn, [CanBeNull] string framework, bool runDotMemoryTests) { @@ -166,7 +165,7 @@ ITargetDefinition TestDefinition(ITargetDefinition targetDefinition, Target depe { LocalPackagesDirectory.CreateDirectory(); ArtifactsDirectory.GlobFiles("*.nupkg") - .ForEach(package => CopyFileToDirectory(package, LocalPackagesDirectory, FileExistsPolicy.Overwrite)); + .ForEach(package => package.CopyToDirectory(LocalPackagesDirectory, ExistsPolicy.FileOverwrite)); }); [PublicAPI] diff --git a/build/_build.csproj b/build/_build.csproj index 7679e4a44..5af72320d 100644 --- a/build/_build.csproj +++ b/build/_build.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net10.0 CS0649;CS0169 .. @@ -11,8 +11,10 @@ - - + + + + diff --git a/global.json b/global.json index 6a14d5d34..99bfe4cad 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "8.0.303", + "version": "10.0.401", "rollForward": "latestFeature" } } diff --git a/source/Halibut.TestProxy/Halibut.TestProxy.csproj b/source/Halibut.TestProxy/Halibut.TestProxy.csproj index 1440b763c..442a2a8e6 100644 --- a/source/Halibut.TestProxy/Halibut.TestProxy.csproj +++ b/source/Halibut.TestProxy/Halibut.TestProxy.csproj @@ -8,16 +8,16 @@ - net48;net8.0 + net48;net10.0 - net8.0 + net10.0 - - - + + + diff --git a/source/Halibut.TestUtils.CompatBinary.Base/Halibut.TestUtils.CompatBinary.Base.csproj b/source/Halibut.TestUtils.CompatBinary.Base/Halibut.TestUtils.CompatBinary.Base.csproj index bc01e10da..f9e4221aa 100644 --- a/source/Halibut.TestUtils.CompatBinary.Base/Halibut.TestUtils.CompatBinary.Base.csproj +++ b/source/Halibut.TestUtils.CompatBinary.Base/Halibut.TestUtils.CompatBinary.Base.csproj @@ -8,10 +8,10 @@ - net48;net8.0 + net48;net10.0 - net8.0 + net10.0 diff --git a/source/Halibut.TestUtils.CompatBinary.Base/SettingsHelper.cs b/source/Halibut.TestUtils.CompatBinary.Base/SettingsHelper.cs index eb453ddb1..5deec8ffb 100644 --- a/source/Halibut.TestUtils.CompatBinary.Base/SettingsHelper.cs +++ b/source/Halibut.TestUtils.CompatBinary.Base/SettingsHelper.cs @@ -76,7 +76,9 @@ public static X509Certificate2 GetClientCertificate() { var octopusCertPath = GetSetting("octopuscertpath"); //Console.WriteLine($"Using octopus cert path: {octopusCertPath}"); +#pragma warning disable SYSLIB0057 // obsolete ctor; kept for identical behaviour on net48 and net10 var clientCert = new X509Certificate2(octopusCertPath); +#pragma warning restore SYSLIB0057 //Console.WriteLine("Octopus/Client cert details " + clientCert); return clientCert; @@ -94,7 +96,9 @@ public static X509Certificate2 GetServiceCertificate() { var tentacleCertPath = GetSetting("tentaclecertpath"); //Console.WriteLine($"Using tentacle cert path: {tentacleCertPath}"); +#pragma warning disable SYSLIB0057 // obsolete ctor; kept for identical behaviour on net48 and net10 var serviceCert = new X509Certificate2(tentacleCertPath); +#pragma warning restore SYSLIB0057 //Console.WriteLine("Tentacle/service cert details " + serviceCert); return serviceCert; diff --git a/source/Halibut.TestUtils.CompatBinary.v4_4_8/Halibut.TestUtils.CompatBinary.v4_4_8.csproj b/source/Halibut.TestUtils.CompatBinary.v4_4_8/Halibut.TestUtils.CompatBinary.v4_4_8.csproj index c6dedf19e..fb8020cb2 100644 --- a/source/Halibut.TestUtils.CompatBinary.v4_4_8/Halibut.TestUtils.CompatBinary.v4_4_8.csproj +++ b/source/Halibut.TestUtils.CompatBinary.v4_4_8/Halibut.TestUtils.CompatBinary.v4_4_8.csproj @@ -9,10 +9,10 @@ - net48;net8.0 + net48;net10.0 - net8.0 + net10.0 diff --git a/source/Halibut.TestUtils.CompatBinary.v5_0_236/Halibut.TestUtils.CompatBinary.v5_0_236.csproj b/source/Halibut.TestUtils.CompatBinary.v5_0_236/Halibut.TestUtils.CompatBinary.v5_0_236.csproj index ab4610de5..f56052e66 100644 --- a/source/Halibut.TestUtils.CompatBinary.v5_0_236/Halibut.TestUtils.CompatBinary.v5_0_236.csproj +++ b/source/Halibut.TestUtils.CompatBinary.v5_0_236/Halibut.TestUtils.CompatBinary.v5_0_236.csproj @@ -9,10 +9,10 @@ - net48;net8.0 + net48;net10.0 - net8.0 + net10.0 diff --git a/source/Halibut.TestUtils.CompatBinary.v6_0_658/Halibut.TestUtils.CompatBinary.v6_0_658.csproj b/source/Halibut.TestUtils.CompatBinary.v6_0_658/Halibut.TestUtils.CompatBinary.v6_0_658.csproj index 347d8068a..d8027b54f 100644 --- a/source/Halibut.TestUtils.CompatBinary.v6_0_658/Halibut.TestUtils.CompatBinary.v6_0_658.csproj +++ b/source/Halibut.TestUtils.CompatBinary.v6_0_658/Halibut.TestUtils.CompatBinary.v6_0_658.csproj @@ -9,14 +9,15 @@ - net48;net8.0 + net48;net10.0 - net8.0 + net10.0 + diff --git a/source/Halibut.TestUtils.Contracts/Halibut.TestUtils.Contracts.csproj b/source/Halibut.TestUtils.Contracts/Halibut.TestUtils.Contracts.csproj index e42348846..e2cb6ba10 100644 --- a/source/Halibut.TestUtils.Contracts/Halibut.TestUtils.Contracts.csproj +++ b/source/Halibut.TestUtils.Contracts/Halibut.TestUtils.Contracts.csproj @@ -8,17 +8,17 @@ - net48;net8.0 + net48;net10.0 - net8.0 + net10.0 all - + diff --git a/source/Halibut.Tests.DotMemory/Certificates.cs b/source/Halibut.Tests.DotMemory/Certificates.cs index bc22c4439..7db89fb20 100644 --- a/source/Halibut.Tests.DotMemory/Certificates.cs +++ b/source/Halibut.Tests.DotMemory/Certificates.cs @@ -26,17 +26,25 @@ static Certificates() //jump through hoops to find certs because the nunit test runner is messing with directories var directory = Path.Combine(Path.GetDirectoryName(new Uri(typeof(Certificates).Assembly.Location).LocalPath)!, "Certificates"); TentacleListeningPfxPath = Path.Combine(directory, "TentacleListening.pfx"); +#pragma warning disable SYSLIB0057 // obsolete ctor; kept for identical behaviour on net48 and net10 TentacleListening = new X509Certificate2(TentacleListeningPfxPath); +#pragma warning restore SYSLIB0057 TentacleListeningPublicThumbprint = TentacleListening.Thumbprint; OctopusPfxPath = Path.Combine(directory, "Octopus.pfx"); +#pragma warning disable SYSLIB0057 // obsolete ctor; kept for identical behaviour on net48 and net10 Octopus = new X509Certificate2(OctopusPfxPath); +#pragma warning restore SYSLIB0057 OctopusPublicThumbprint = Octopus.Thumbprint; TentaclePollingPfxPath = Path.Combine(directory, "TentaclePolling.pfx"); +#pragma warning disable SYSLIB0057 // obsolete ctor; kept for identical behaviour on net48 and net10 TentaclePolling = new X509Certificate2(TentaclePollingPfxPath); +#pragma warning restore SYSLIB0057 TentaclePollingPublicThumbprint = TentaclePolling.Thumbprint; +#pragma warning disable SYSLIB0057 // obsolete ctor; kept for identical behaviour on net48 and net10 Ssl = new X509Certificate2(Path.Combine(directory, "Ssl.pfx"), "password"); +#pragma warning restore SYSLIB0057 SslThumbprint = Ssl.Thumbprint; } } diff --git a/source/Halibut.Tests.DotMemory/Halibut.Tests.DotMemory.csproj b/source/Halibut.Tests.DotMemory/Halibut.Tests.DotMemory.csproj index 3b556a710..f50f0a78c 100644 --- a/source/Halibut.Tests.DotMemory/Halibut.Tests.DotMemory.csproj +++ b/source/Halibut.Tests.DotMemory/Halibut.Tests.DotMemory.csproj @@ -10,10 +10,10 @@ enable - net48;net8.0 + net48;net10.0 - net8.0 + net10.0 @@ -29,19 +29,19 @@ - - - - - - - + + + + + + + - + - + - + diff --git a/source/Halibut.Tests/ExceptionContractFixture.cs b/source/Halibut.Tests/ExceptionContractFixture.cs index eb1ae5bc0..a59f8d9c4 100644 --- a/source/Halibut.Tests/ExceptionContractFixture.cs +++ b/source/Halibut.Tests/ExceptionContractFixture.cs @@ -151,7 +151,9 @@ public async Task WhenTheListeningRequestFailsToBeSent_AsTheServiceRejectsTheCon .And.Message.Should().ContainAny( $"An error occurred when sending a request to '{clientAndService.ServiceUri}', before the request could begin: Unable to read data from the transport connection", $"An error occurred when sending a request to '{clientAndService.ServiceUri}', before the request could begin: Unable to write data to the transport connection", + // .NET Framework's SslStream message has a leading space; modern .NET's does not $"An error occurred when sending a request to '{clientAndService.ServiceUri}', before the request could begin: Received an unexpected EOF or 0 bytes from the transport stream", + $"An error occurred when sending a request to '{clientAndService.ServiceUri}', before the request could begin: Received an unexpected EOF or 0 bytes from the transport stream", $"An error occurred when sending a request to '{clientAndService.ServiceUri}', before the request could begin: Transport endpoint is not connected"); } diff --git a/source/Halibut.Tests/FriendlyHtmlPageTests.cs b/source/Halibut.Tests/FriendlyHtmlPageTests.cs index 9bb4ffadc..7ede856a9 100644 --- a/source/Halibut.Tests/FriendlyHtmlPageTests.cs +++ b/source/Halibut.Tests/FriendlyHtmlPageTests.cs @@ -121,11 +121,15 @@ static async Task>> GetHeadersIgnoringCertific using (var client = new HttpClient(httpClientHandler)) { var headers = new List>(); +#pragma warning disable SYSLIB0014 var existingServerCertificateValidationCallback = ServicePointManager.ServerCertificateValidationCallback; +#pragma warning restore SYSLIB0014 try { // We need to ignore server certificate validation errors - the server certificate is self-signed +#pragma warning disable SYSLIB0014 ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true; +#pragma warning restore SYSLIB0014 var response = await client.GetAsync(uri); foreach (var key in response.Headers) { @@ -135,7 +139,9 @@ static async Task>> GetHeadersIgnoringCertific finally { // And restore it back to default behaviour +#pragma warning disable SYSLIB0014 ServicePointManager.ServerCertificateValidationCallback = existingServerCertificateValidationCallback; +#pragma warning restore SYSLIB0014 } return headers; diff --git a/source/Halibut.Tests/Halibut.Tests.csproj b/source/Halibut.Tests/Halibut.Tests.csproj index 602280ad8..526854c7d 100644 --- a/source/Halibut.Tests/Halibut.Tests.csproj +++ b/source/Halibut.Tests/Halibut.Tests.csproj @@ -7,15 +7,15 @@ true false 9.0 - VSTHRD002,VSTHRD003;VSTHRD103 + VSTHRD002,VSTHRD003;VSTHRD103;CA2022 enable true - net48;net8.0 + net48;net10.0 - net8.0 + net10.0 @@ -34,30 +34,30 @@ - - - - - - - - - - + + + + + + + + + + - - + + - + - + $(DefineConstants);SUPPORTS_WEB_SOCKET_CLIENT;DOES_NOT_SUPPORT_CANCELLATION_ON_SOCKETS - + $(DefineConstants);HAS_TCP_KEEP_ALIVE_SOCKET_OPTIONS diff --git a/source/Halibut.Tests/Queue/Redis/Utils/RedisContainerBuilder.cs b/source/Halibut.Tests/Queue/Redis/Utils/RedisContainerBuilder.cs index 510a64df7..07b6f0155 100644 --- a/source/Halibut.Tests/Queue/Redis/Utils/RedisContainerBuilder.cs +++ b/source/Halibut.Tests/Queue/Redis/Utils/RedisContainerBuilder.cs @@ -86,8 +86,7 @@ public RedisContainer Build() // permissions, so Redis (running as 1001) would fail to start if the checkout is not readable by other users. var redisConfigArguments = RedisConfigFileToArguments(Path.Combine(redisConfigPath, "redis.conf")); - var container = new ContainerBuilder() - .WithImage(_image) + var container = new ContainerBuilder(_image) .WithPortBinding(hostPort, 6379) // Start redis-server directly, the official image's entrypoint loads the Redis 8 modules (JSON, search etc.) which Octopus Cloud's image does not. .WithEntrypoint("redis-server") @@ -98,7 +97,7 @@ public RedisContainer Build() .WithCreateParameterModifier(parameters => { parameters.User = "1001:1001"; - parameters.HostConfig.ReadonlyRootfs = true; + parameters.HostConfig!.ReadonlyRootfs = true; parameters.HostConfig.CapDrop = new List { "ALL" }; parameters.HostConfig.SecurityOpt = new List { "no-new-privileges" }; }) diff --git a/source/Halibut.Tests/Support/AsyncEnumerableCompat.cs b/source/Halibut.Tests/Support/AsyncEnumerableCompat.cs new file mode 100644 index 000000000..9b5ed6f46 --- /dev/null +++ b/source/Halibut.Tests/Support/AsyncEnumerableCompat.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Halibut.Tests.Support +{ + // On net10.0 the framework's System.Linq.AsyncEnumerable and the System.Linq.Async package + // (pulled in by System.Interactive.Async on net48) both define ToAsyncEnumerable and SelectAwait-style + // operators, which makes calls ambiguous or unavailable. These helpers give both targets one implementation. + public static class AsyncEnumerableCompat + { + public static async IAsyncEnumerable ToAsyncEnumerableCompat(this IEnumerable source) + { + foreach (var item in source) + { + yield return item; + } + } + + public static async IAsyncEnumerable SelectAwaitCompat(this IAsyncEnumerable source, Func> selector) + { + await foreach (var item in source) + { + yield return await selector(item); + } + } + } +} diff --git a/source/Halibut.Tests/Support/Certificates.cs b/source/Halibut.Tests/Support/Certificates.cs index bd0a31f1a..d1c13d164 100644 --- a/source/Halibut.Tests/Support/Certificates.cs +++ b/source/Halibut.Tests/Support/Certificates.cs @@ -31,23 +31,33 @@ static Certificates() //jump through hoops to find certs because the nunit test runner is messing with directories var directory = Path.Combine(Path.GetDirectoryName(new Uri(typeof(Certificates).Assembly.Location).LocalPath)!, "Certificates"); TentacleListeningPfxPath = Path.Combine(directory, "TentacleListening.pfx"); +#pragma warning disable SYSLIB0057 TentacleListening = new X509Certificate2(TentacleListeningPfxPath); +#pragma warning restore SYSLIB0057 TentacleListeningPublicThumbprint = TentacleListening.Thumbprint; OctopusPfxPath = Path.Combine(directory, "Octopus.pfx"); +#pragma warning disable SYSLIB0057 Octopus = new X509Certificate2(OctopusPfxPath); +#pragma warning restore SYSLIB0057 OctopusPublicThumbprint = Octopus.Thumbprint; TentaclePollingPfxPath = Path.Combine(directory, "TentaclePolling.pfx"); +#pragma warning disable SYSLIB0057 TentaclePolling = new X509Certificate2(TentaclePollingPfxPath); +#pragma warning restore SYSLIB0057 TentaclePollingPublicThumbprint = TentaclePolling.Thumbprint; WrongPfxPath = Path.Combine(directory, "WrongCert.pfx"); +#pragma warning disable SYSLIB0057 Wrong = new X509Certificate2(WrongPfxPath); +#pragma warning restore SYSLIB0057 WrongPublicThumbprint = Wrong.Thumbprint; sslPfxPath = Path.Combine(directory, "Ssl.pfx"); +#pragma warning disable SYSLIB0057 Ssl = new X509Certificate2(sslPfxPath, "password"); +#pragma warning restore SYSLIB0057 SslThumbprint = Ssl.Thumbprint; } } diff --git a/source/Halibut.Tests/Support/Streams/SynIoRecording/SyncIoRecordingWebSocketStream.cs b/source/Halibut.Tests/Support/Streams/SynIoRecording/SyncIoRecordingWebSocketStream.cs index 4bb1c57f5..e0ad329d9 100644 --- a/source/Halibut.Tests/Support/Streams/SynIoRecording/SyncIoRecordingWebSocketStream.cs +++ b/source/Halibut.Tests/Support/Streams/SynIoRecording/SyncIoRecordingWebSocketStream.cs @@ -5,7 +5,7 @@ namespace Halibut.Tests.Support.Streams.SynIoRecording { - public class SyncIoRecordingWebSocketStream : WebSocketStream, IRecordSyncIo + public class SyncIoRecordingWebSocketStream : Halibut.Transport.Protocol.WebSocketStream, IRecordSyncIo { readonly List syncCalls = new(); diff --git a/source/Halibut.Tests/Support/TempDisposableCertAndThumbprint.cs b/source/Halibut.Tests/Support/TempDisposableCertAndThumbprint.cs index 2c952fec0..cf2469482 100644 --- a/source/Halibut.Tests/Support/TempDisposableCertAndThumbprint.cs +++ b/source/Halibut.Tests/Support/TempDisposableCertAndThumbprint.cs @@ -49,7 +49,9 @@ public static ICertAndThumbprint CreateSelfSigned(DisposableCollection disposedB var bytes = certificate.Export(X509ContentType.Pfx); var filePath = Path.Combine(tempDir.DirectoryPath, $"{name}.pfx"); File.WriteAllBytes(filePath, bytes); +#pragma warning disable SYSLIB0057 var disposableCert = new TempDisposableCertAndThumbprint(tempDir, filePath, new X509Certificate2(bytes)); +#pragma warning restore SYSLIB0057 disposedBy.Add(disposableCert); return disposableCert; } diff --git a/source/Halibut.Tests/TestServices/AsyncComplexObjectService.cs b/source/Halibut.Tests/TestServices/AsyncComplexObjectService.cs index c37262a37..b50faa4b0 100644 --- a/source/Halibut.Tests/TestServices/AsyncComplexObjectService.cs +++ b/source/Halibut.Tests/TestServices/AsyncComplexObjectService.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Halibut.Tests.Support; using Halibut.Tests.Util; using Halibut.TestUtils.Contracts; @@ -28,13 +29,13 @@ public async Task ProcessAsync(ComplexObjectMulti { ChildPayload1 = await ReadIntoNewDataStream(request.Child1!.ChildPayload1, cancellationToken), ChildPayload2 = await ReadIntoNewDataStream(request.Child1!.ChildPayload2, cancellationToken), - ListOfStreams = await request.Child1.ListOfStreams!.ToAsyncEnumerable().SelectAwait(async ds => await ReadIntoNewDataStream(ds, cancellationToken)).ToListAsync(cancellationToken), + ListOfStreams = await request.Child1.ListOfStreams!.ToAsyncEnumerableCompat().SelectAwaitCompat(async ds => await ReadIntoNewDataStream(ds, cancellationToken)).ToListAsync(cancellationToken), DictionaryPayload = request.Child1.DictionaryPayload!.ToDictionary(pair => pair.Key, pair => pair.Value), }, Child2 = new ComplexChild2 { EnumPayload = request.Child2!.EnumPayload, - ComplexPayloadSet = await request.Child2.ComplexPayloadSet!.ToAsyncEnumerable().SelectAwait(async x => new ComplexPair(x.EnumValue, await ReadIntoNewDataStream(x.Payload, cancellationToken))).ToHashSetAsync(cancellationToken) + ComplexPayloadSet = await request.Child2.ComplexPayloadSet!.ToAsyncEnumerableCompat().SelectAwaitCompat(async x => new ComplexPair(x.EnumValue, await ReadIntoNewDataStream(x.Payload, cancellationToken))).ToHashSetAsync(cancellationToken: cancellationToken) } }; } diff --git a/source/Halibut.Tests/Transport/Protocol/MessageSerializerFixture.cs b/source/Halibut.Tests/Transport/Protocol/MessageSerializerFixture.cs index c36acdd85..3ac48bedb 100644 --- a/source/Halibut.Tests/Transport/Protocol/MessageSerializerFixture.cs +++ b/source/Halibut.Tests/Transport/Protocol/MessageSerializerFixture.cs @@ -16,6 +16,13 @@ namespace Halibut.Tests.Transport.Protocol { public class MessageSerializerFixture : BaseTest { +#if NETFRAMEWORK + const long ExpectedCompressedBytes = 55; +#else + // .NET 9+ uses zlib-ng for DeflateStream, which produces slightly different output. + const long ExpectedCompressedBytes = 57; +#endif + [Test] [TestCaseSource(typeof(MessageSerializerTestCaseSource))] public async Task SendReceiveMessageShouldRoundTrip(MessageSerializerTestCase testCase) @@ -52,8 +59,8 @@ public async Task WriteMessage_ObservesThatMessageIsWritten(MessageSerializerTes } var writtenMessage = messageSerializerObserver.MessagesWritten.Should().ContainSingle().Subject; - writtenMessage.CompressedBytesWritten.Should().Be(55); - var expectedCompressedBytesWrittenIntoMemory = testCase.AsyncMemoryLimit > 55 ? 55 : 0; + writtenMessage.CompressedBytesWritten.Should().Be(ExpectedCompressedBytes); + var expectedCompressedBytesWrittenIntoMemory = testCase.AsyncMemoryLimit > ExpectedCompressedBytes ? ExpectedCompressedBytes : 0; writtenMessage.CompressedBytesWrittenIntoMemory.Should().Be(expectedCompressedBytesWrittenIntoMemory); messageSerializerObserver.MessagesRead.Should().BeEmpty(); } @@ -83,7 +90,7 @@ public async Task ReadMessage_ObservesThatMessageIsRead(MessageSerializerTestCas } var readMessage = messageSerializerObserver.MessagesRead.Should().ContainSingle().Subject; - readMessage.CompressedBytesRead.Should().Be(55); + readMessage.CompressedBytesRead.Should().Be(ExpectedCompressedBytes); readMessage.DecompressedBytesRead.Should().Be(120); var expectedDecompressedBytesReadIntoMemory = Math.Min(testCase.AsyncMemoryLimit, 120); readMessage.DecompressedBytesReadIntoMemory.Should().Be(expectedDecompressedBytesReadIntoMemory); @@ -210,7 +217,7 @@ public async Task ReadMessage_Rewindable_ObservesThatMessageIsRead(MessageSerial } var readMessage = messageSerializerObserver.MessagesRead.Should().ContainSingle().Subject; - readMessage.CompressedBytesRead.Should().Be(55); + readMessage.CompressedBytesRead.Should().Be(ExpectedCompressedBytes); readMessage.DecompressedBytesRead.Should().Be(120); var expectedDecompressedBytesReadIntoMemory = Math.Min(testCase.AsyncMemoryLimit, 120); readMessage.DecompressedBytesReadIntoMemory.Should().Be(expectedDecompressedBytesReadIntoMemory); @@ -272,7 +279,7 @@ public async Task ReadMessage_Rewindable_ShouldNotObserveTrailingDataWhenReading } var readMessage = messageSerializerObserver.MessagesRead.Should().ContainSingle().Subject; - readMessage.CompressedBytesRead.Should().Be(55); + readMessage.CompressedBytesRead.Should().Be(ExpectedCompressedBytes); readMessage.DecompressedBytesRead.Should().Be(120); var expectedDecompressedBytesReadIntoMemory = Math.Min(testCase.AsyncMemoryLimit, 120); readMessage.DecompressedBytesReadIntoMemory.Should().Be(expectedDecompressedBytesReadIntoMemory); diff --git a/source/Halibut.Tests/UsageFixture.cs b/source/Halibut.Tests/UsageFixture.cs index 4de3035a9..0be41209d 100644 --- a/source/Halibut.Tests/UsageFixture.cs +++ b/source/Halibut.Tests/UsageFixture.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using FluentAssertions; using Halibut.Exceptions; +using Halibut.Tests.Support; using Halibut.Tests.Support.TestAttributes; using Halibut.Tests.Support.TestCases; using Halibut.Tests.TestServices.Async; @@ -256,8 +257,8 @@ public async Task OctopusCanSendAndReceiveComplexObjects_WithMultipleComplexChil response.Child1.ChildPayload2.Should().NotBeSameAs(request.Child1.ChildPayload2); (await response.Child1.ChildPayload2!.ReadAsString(CancellationToken)).Should().Be(childPayload2); response.Child1.ListOfStreams.Should().NotBeSameAs(request.Child1.ListOfStreams); - (await response.Child1.ListOfStreams!.ToAsyncEnumerable() - .SelectAwait(async x => await x.ReadAsString(CancellationToken)) + (await response.Child1.ListOfStreams!.ToAsyncEnumerableCompat() + .SelectAwaitCompat(async x => await x.ReadAsString(CancellationToken)) .ToListAsync(CancellationToken)) .Should().BeEquivalentTo(list); response.Child1.DictionaryPayload.Should().NotBeSameAs(request.Child1.DictionaryPayload); @@ -266,8 +267,8 @@ public async Task OctopusCanSendAndReceiveComplexObjects_WithMultipleComplexChil response.Child2.Should().NotBeSameAs(request.Child2); response.Child2!.EnumPayload.Should().Be(enumValue); response.Child2.ComplexPayloadSet.Should().NotBeSameAs(request.Child2.ComplexPayloadSet); - (await response.Child2.ComplexPayloadSet!.ToAsyncEnumerable() - .SelectAwait(async x => new ComplexPair(x.EnumValue, await x.Payload.ReadAsString(CancellationToken))) + (await response.Child2.ComplexPayloadSet!.ToAsyncEnumerableCompat() + .SelectAwaitCompat(async x => new ComplexPair(x.EnumValue, await x.Payload.ReadAsString(CancellationToken))) .ToArrayAsync()) .ToHashSet() .Should() diff --git a/source/Halibut/Halibut.csproj b/source/Halibut/Halibut.csproj index 383684887..46b608079 100644 --- a/source/Halibut/Halibut.csproj +++ b/source/Halibut/Halibut.csproj @@ -19,10 +19,10 @@ enable - net48;net8.0 + net48;net10.0 - net8.0 + net10.0 True @@ -32,18 +32,17 @@ - + - + - + - @@ -51,7 +50,7 @@ - + $(DefineConstants);LIBLOG_PORTABLE;HAS_TCP_KEEP_ALIVE_SOCKET_OPTIONS diff --git a/source/Halibut/Transport/ClientCertificateValidator.cs b/source/Halibut/Transport/ClientCertificateValidator.cs index ea37d453a..b5929268f 100644 --- a/source/Halibut/Transport/ClientCertificateValidator.cs +++ b/source/Halibut/Transport/ClientCertificateValidator.cs @@ -15,7 +15,9 @@ public ClientCertificateValidator(ServiceEndPoint endPoint) public bool Validate(object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslpolicyerrors) { +#pragma warning disable SYSLIB0057 // obsolete ctor; kept for identical behaviour on net48 and net10 var providedCert = new X509Certificate2(certificate!.Export(X509ContentType.Cert), (string)null!); // Copy the cert so that we can reference it later +#pragma warning restore SYSLIB0057 var providedThumbprint = providedCert.Thumbprint; if (providedThumbprint == endPoint.RemoteThumbprint) diff --git a/source/Halibut/Transport/DiscoveryClient.cs b/source/Halibut/Transport/DiscoveryClient.cs index c92280702..cedaa5edb 100644 --- a/source/Halibut/Transport/DiscoveryClient.cs +++ b/source/Halibut/Transport/DiscoveryClient.cs @@ -61,7 +61,9 @@ await ssl.AuthenticateAsClientEnforcingTimeout( throw new Exception("The server did not provide an SSL certificate"); #pragma warning disable PC001 // API not supported on all platforms - X509Certificate2 not supported on macOS +#pragma warning disable SYSLIB0057 // obsolete ctor; kept for identical behaviour on net48 and net10 return new ServiceEndPoint(serviceEndpoint.BaseUri, new X509Certificate2(ssl.RemoteCertificate.Export(X509ContentType.Cert), (string)null!).Thumbprint, halibutTimeoutsAndLimits); +#pragma warning restore SYSLIB0057 #pragma warning restore PC001 // API not supported on all platforms - X509Certificate2 not supported on macOS } } diff --git a/source/Halibut/Transport/SecureListener.cs b/source/Halibut/Transport/SecureListener.cs index a32c0ad64..40db01b3d 100644 --- a/source/Halibut/Transport/SecureListener.cs +++ b/source/Halibut/Transport/SecureListener.cs @@ -457,7 +457,9 @@ async Task SendFriendlyHtmlPage(Stream stream) return null; } +#pragma warning disable SYSLIB0057 // obsolete ctor; kept for identical behaviour on net48 and net10 var thumbprint = new X509Certificate2(stream.RemoteCertificate.Export(X509ContentType.Cert), (string)null!).Thumbprint; +#pragma warning restore SYSLIB0057 return thumbprint; } diff --git a/source/Halibut/Transport/SecureWebSocketListener.cs b/source/Halibut/Transport/SecureWebSocketListener.cs index 1807a469f..ec562fb26 100644 --- a/source/Halibut/Transport/SecureWebSocketListener.cs +++ b/source/Halibut/Transport/SecureWebSocketListener.cs @@ -233,7 +233,9 @@ async Task Authorize(HttpListenerContext context, string clientName) return false; } +#pragma warning disable SYSLIB0057 // obsolete ctor; kept for identical behaviour on net48 and net10 var thumbprint = new X509Certificate2(certificate.Export(X509ContentType.Cert), (string)null!).Thumbprint; +#pragma warning restore SYSLIB0057 var isAuthorized = verifyClientThumbprint(thumbprint); if (!isAuthorized) diff --git a/source/Halibut/Transport/ServerCertificateInterceptor.cs b/source/Halibut/Transport/ServerCertificateInterceptor.cs index 33b6b55b8..30b169a22 100644 --- a/source/Halibut/Transport/ServerCertificateInterceptor.cs +++ b/source/Halibut/Transport/ServerCertificateInterceptor.cs @@ -38,7 +38,9 @@ static void Initialize() { if (certificates.ContainsKey(clientId)) { +#pragma warning disable SYSLIB0057 // obsolete ctor; kept for identical behaviour on net48 and net10 var providedCert = new X509Certificate2(certificate.Export(X509ContentType.Cert), (string)null!); // Copy the cert so that we can reference it later +#pragma warning restore SYSLIB0057 certificates[clientId] = providedCert; return true; } diff --git a/source/Halibut/Transport/Streams/StreamFactory.cs b/source/Halibut/Transport/Streams/StreamFactory.cs index 1f941bc48..87f7719e4 100644 --- a/source/Halibut/Transport/Streams/StreamFactory.cs +++ b/source/Halibut/Transport/Streams/StreamFactory.cs @@ -15,7 +15,7 @@ public Stream CreateStream(TcpClient client) public Stream CreateStream(WebSocket webSocket) { - var webSocketStream = new WebSocketStream(webSocket); + var webSocketStream = new Halibut.Transport.Protocol.WebSocketStream(webSocket); var networkStream = new NetworkTimeoutStream(webSocketStream); // When synchronous serialization is performed, it will call the synchronous versions of Read/Write. diff --git a/source/Octopus.TestPortForwarder/Octopus.TestPortForwarder.csproj b/source/Octopus.TestPortForwarder/Octopus.TestPortForwarder.csproj index 1dff29309..f302e3471 100644 --- a/source/Octopus.TestPortForwarder/Octopus.TestPortForwarder.csproj +++ b/source/Octopus.TestPortForwarder/Octopus.TestPortForwarder.csproj @@ -8,13 +8,13 @@ - net48;net8.0 + net48;net10.0 - net8.0 + net10.0 - +