From 74fefad2ad70e6a65bbededca38e285b61d84124 Mon Sep 17 00:00:00 2001 From: jsonbailey Date: Fri, 12 Jun 2026 17:30:56 -0500 Subject: [PATCH] feat: Update target frameworks to net8.0 Replace netcoreapp3.1 and net6.0 with net8.0 (keeping netstandard2.0 and net462), mirroring the dotnet-core packages. This is not a breaking change: netstandard2.0/net462 still cover .NET Framework consumers, netcoreapp3.1 is not used by the consuming SDKs, and net6.0/netcoreapp3.1 are out of support, so no major version bump is required. The JsonConverterHelpers ref-struct helpers (ArrayHelper/ObjectHelper) could not be used under net8.0 because the .NET 7+ runtime enables byref-field ref-safety analysis regardless of LangVersion, causing CS8350/CS8352 at every call site. Annotate the Utf8JsonReader parameters as 'scoped' to declare that the helpers never capture a reference to the reader, and raise LangVersion to 11 so the annotation is available. This unblocks net8.0 for all consumers. Simplify the HttpProperties handler guard from '#if NETCOREAPP || NET6_0' to '#if NETCOREAPP'. The branch selects SocketsHttpHandler (for ConnectTimeout support), which exists on all .NET Core 2.1+ / .NET 5+ targets, so there is no version floor to enforce; the unversioned NETCOREAPP symbol already covers every such target and the '|| NET6_0' clause was redundant. Update CI and release actions to install the 8.0 SDK and target net8.0. --- .github/actions/build-release/action.yml | 4 +--- .github/actions/ci/action.yml | 4 +--- .github/actions/full-release/action.yml | 2 +- .github/actions/publish-package/action.yml | 4 +--- .github/workflows/build-test.yml | 3 +-- .../Http/HttpProperties.cs | 2 +- .../JsonConverterHelpers.cs | 14 +++++++------- .../LaunchDarkly.InternalSdk.csproj | 6 +++--- .../JsonConverterHelpersTest.cs | 8 ++++---- .../LaunchDarkly.InternalSdk.Tests.csproj | 4 +++- 10 files changed, 23 insertions(+), 28 deletions(-) diff --git a/.github/actions/build-release/action.yml b/.github/actions/build-release/action.yml index ba231d4..7b8e790 100644 --- a/.github/actions/build-release/action.yml +++ b/.github/actions/build-release/action.yml @@ -11,9 +11,7 @@ runs: - name: Setup dotnet build tools uses: actions/setup-dotnet@v4 with: - dotnet-version: | - 6.0 - 7.0 + dotnet-version: 8.0 - name: Display dotnet version shell: bash diff --git a/.github/actions/ci/action.yml b/.github/actions/ci/action.yml index 8c2dc10..b0c6119 100644 --- a/.github/actions/ci/action.yml +++ b/.github/actions/ci/action.yml @@ -11,9 +11,7 @@ runs: - name: Setup dotnet build tools uses: actions/setup-dotnet@v4 with: - dotnet-version: | - 6.0 - 7.0 + dotnet-version: 8.0 - run: dotnet --version shell: bash diff --git a/.github/actions/full-release/action.yml b/.github/actions/full-release/action.yml index c596ce6..8177c27 100644 --- a/.github/actions/full-release/action.yml +++ b/.github/actions/full-release/action.yml @@ -31,7 +31,7 @@ runs: - name: CI check uses: ./.github/actions/ci with: - framework_target: "net6.0" + framework_target: "net8.0" - uses: launchdarkly/gh-actions/actions/release-secrets@release-secrets-v1.2.0 name: Get secrets diff --git a/.github/actions/publish-package/action.yml b/.github/actions/publish-package/action.yml index 37a8270..10cf8a7 100644 --- a/.github/actions/publish-package/action.yml +++ b/.github/actions/publish-package/action.yml @@ -13,9 +13,7 @@ runs: - name: Setup dotnet build tools uses: actions/setup-dotnet@v4 with: - dotnet-version: | - 6.0 - 7.0 + dotnet-version: 8.0 - name: Install Workloads shell: bash diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index a2dcfa6..30c39eb 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -15,8 +15,7 @@ jobs: strategy: matrix: framework: - - { target: 'netcoreapp3.1', image: 'sdk:3.1-focal' } - - { target: 'net6.0', image: 'sdk:6.0-focal' } + - { target: 'net8.0', image: 'sdk:8.0' } runs-on: ubuntu-latest container: mcr.microsoft.com/dotnet/${{ matrix.framework.image }} env: diff --git a/src/LaunchDarkly.InternalSdk/Http/HttpProperties.cs b/src/LaunchDarkly.InternalSdk/Http/HttpProperties.cs index 7b043a6..c2e3ce7 100644 --- a/src/LaunchDarkly.InternalSdk/Http/HttpProperties.cs +++ b/src/LaunchDarkly.InternalSdk/Http/HttpProperties.cs @@ -267,7 +267,7 @@ public HttpMessageHandler NewHttpMessageHandler() => private static HttpMessageHandler DefaultHttpMessageHandlerFactory(HttpProperties props) { -#if NETCOREAPP || NET6_0 +#if NETCOREAPP return new SocketsHttpHandler { ConnectTimeout = props.ConnectTimeout, diff --git a/src/LaunchDarkly.InternalSdk/JsonConverterHelpers.cs b/src/LaunchDarkly.InternalSdk/JsonConverterHelpers.cs index b8fea11..0004b1d 100644 --- a/src/LaunchDarkly.InternalSdk/JsonConverterHelpers.cs +++ b/src/LaunchDarkly.InternalSdk/JsonConverterHelpers.cs @@ -185,7 +185,7 @@ public static void WriteLdValueIfNotNull(Utf8JsonWriter w, string name, LdValue /// the JSON reader /// an /// if the next token is not the beginning of an array - public static ArrayHelper RequireArray(ref Utf8JsonReader reader) => + public static ArrayHelper RequireArray(scoped ref Utf8JsonReader reader) => new ArrayHelper(ref reader, false); /// @@ -195,7 +195,7 @@ public static ArrayHelper RequireArray(ref Utf8JsonReader reader) => /// the JSON reader /// an /// if the next token is not the beginning of an array or null - public static ArrayHelper RequireArrayOrNull(ref Utf8JsonReader reader) => + public static ArrayHelper RequireArrayOrNull(scoped ref Utf8JsonReader reader) => new ArrayHelper(ref reader, true); /// @@ -205,7 +205,7 @@ public static ArrayHelper RequireArrayOrNull(ref Utf8JsonReader reader) => /// the JSON reader /// an /// if the next token is not the beginning of an object - public static ObjectHelper RequireObject(ref Utf8JsonReader reader) + public static ObjectHelper RequireObject(scoped ref Utf8JsonReader reader) { if (reader.TokenType == JsonTokenType.None) { @@ -222,7 +222,7 @@ public static ObjectHelper RequireObject(ref Utf8JsonReader reader) /// the JSON reader /// an /// if the next token is not the beginning of an object or null - public static ObjectHelper RequireObjectOrNull(ref Utf8JsonReader reader) + public static ObjectHelper RequireObjectOrNull(scoped ref Utf8JsonReader reader) { if (reader.TokenType == JsonTokenType.None) { @@ -245,7 +245,7 @@ public ref struct ArrayHelper { private readonly bool _empty; - internal ArrayHelper(ref Utf8JsonReader reader, bool allowNull) + internal ArrayHelper(scoped ref Utf8JsonReader reader, bool allowNull) { if (reader.TokenType == JsonTokenType.None) { @@ -268,7 +268,7 @@ internal ArrayHelper(ref Utf8JsonReader reader, bool allowNull) /// /// the JSON reader (this must be passed again due to ref struct rules) /// true if there is an element, false if this is the end - public bool Next(ref Utf8JsonReader reader) => + public bool Next(scoped ref Utf8JsonReader reader) => !_empty && reader.Read() && reader.TokenType != JsonTokenType.EndArray; } @@ -360,7 +360,7 @@ public ObjectHelper WithRequiredProperties(params string[] propertyNames) => /// /// the JSON reader (this must be passed again due to ref struct rules) /// true if there is a property, false if this is the end - public bool Next(ref Utf8JsonReader reader) + public bool Next(scoped ref Utf8JsonReader reader) { if (!_defined) { diff --git a/src/LaunchDarkly.InternalSdk/LaunchDarkly.InternalSdk.csproj b/src/LaunchDarkly.InternalSdk/LaunchDarkly.InternalSdk.csproj index 5c96876..7ad34a9 100644 --- a/src/LaunchDarkly.InternalSdk/LaunchDarkly.InternalSdk.csproj +++ b/src/LaunchDarkly.InternalSdk/LaunchDarkly.InternalSdk.csproj @@ -8,12 +8,12 @@ an environment variable is that we want to be able to run CI tests using .NET SDKs that may not support all of these target frameworks. --> - netstandard2.0;netcoreapp3.1;net462;net6.0 + netstandard2.0;net462;net8.0 $(BUILDFRAMEWORKS) portable LaunchDarkly.InternalSdk Library - 7.3 + 11 LaunchDarkly.InternalSdk LaunchDarkly.Sdk.Internal LaunchDarkly internal common code for .NET and Xamarin clients @@ -27,7 +27,7 @@ main - + diff --git a/test/LaunchDarkly.InternalSdk.Tests/JsonConverterHelpersTest.cs b/test/LaunchDarkly.InternalSdk.Tests/JsonConverterHelpersTest.cs index 836c36d..3908d12 100644 --- a/test/LaunchDarkly.InternalSdk.Tests/JsonConverterHelpersTest.cs +++ b/test/LaunchDarkly.InternalSdk.Tests/JsonConverterHelpersTest.cs @@ -184,7 +184,7 @@ public void NonEmptyArray() VerifyNonEmptyArray(ref r2, ref a2); } - private void VerifyNonEmptyArray(ref Utf8JsonReader r, ref ArrayHelper a) + private void VerifyNonEmptyArray(scoped ref Utf8JsonReader r, ref ArrayHelper a) { Assert.True(a.Next(ref r)); Assert.Equal(10, r.GetInt32()); @@ -207,7 +207,7 @@ public void EmptyArray() VerifyEmptyArray(ref r2, ref a2); } - private void VerifyEmptyArray(ref Utf8JsonReader r, ref ArrayHelper a) => + private void VerifyEmptyArray(scoped ref Utf8JsonReader r, ref ArrayHelper a) => Assert.False(a.Next(ref r)); [Fact] @@ -242,7 +242,7 @@ public void NonEmptyObject() VerifyNonEmptyObject(ref r2, ref o2); } - private void VerifyNonEmptyObject(ref Utf8JsonReader r, ref ObjectHelper o) + private void VerifyNonEmptyObject(scoped ref Utf8JsonReader r, ref ObjectHelper o) { Assert.True(o.Next(ref r)); Assert.Equal("a", o.Name); @@ -267,7 +267,7 @@ public void EmptyObject() VerifyEmptyObject(ref r2, ref o2); } - private void VerifyEmptyObject(ref Utf8JsonReader r, ref ObjectHelper o) => + private void VerifyEmptyObject(scoped ref Utf8JsonReader r, ref ObjectHelper o) => Assert.False(o.Next(ref r)); [Fact] diff --git a/test/LaunchDarkly.InternalSdk.Tests/LaunchDarkly.InternalSdk.Tests.csproj b/test/LaunchDarkly.InternalSdk.Tests/LaunchDarkly.InternalSdk.Tests.csproj index b96b705..61943c7 100644 --- a/test/LaunchDarkly.InternalSdk.Tests/LaunchDarkly.InternalSdk.Tests.csproj +++ b/test/LaunchDarkly.InternalSdk.Tests/LaunchDarkly.InternalSdk.Tests.csproj @@ -1,9 +1,11 @@ - netcoreapp3.1;net462;net6.0 + net462;net8.0 $(TESTFRAMEWORK) LaunchDarkly.InternalSdk.Tests LaunchDarkly.Sdk.Internal + + 11 1.2.3 1.2.3 false