Skip to content

feat(stjm): support .NET 8 and .NET 9 without JSON upgrades - #280

Draft
LiteracyFanatic wants to merge 1 commit into
egil:mainfrom
LiteracyFanatic:codex/stjm-net8-support
Draft

LiteracyFanatic wants to merge 1 commit into
egil:mainfrom
LiteracyFanatic:codex/stjm-net8-support

Conversation

@LiteracyFanatic

@LiteracyFanatic LiteracyFanatic commented Oct 2, 2026 •

Copy link
Copy Markdown

.NET 8 and .NET 9 applications currently cannot consume the migration package. Adding a newer System.Text.Json package would also force a dependency upgrade in hosts that already load JSON 8. In a Civil 3D 2025 host test, that approach failed with FileLoadException for System.Text.Json 10.0.0.0; the new net8.0 asset passed using the host's existing JSON 8 assembly.

Add net8.0 and net9.0 alongside net10.0 and net11.0 across the migration library, tests, samples, and benchmarks. The only runtime compatibility branch reads JsonTypeInfo.ElementType through the existing StjInternals UnsafeAccessor pattern on .NET 8, where this property is internal. Reading the resolved JSON contract preserves collection routing semantics, including inherited collections with multiple IEnumerable interfaces, without duplicating System.Text.Json's converter-selection rules or adding a runtime package dependency. The .NET 9 and newer assets use the public property path; union support remains .NET 11-only.

Add 36 collection-routing cases and separate resolver snapshot retention, newer-runtime decorator retention, and actual cycle termination on .NET 8/9. Document the snapshot-before-decoration pattern and keep linked compatibility guidance consistent. Extend CI to install .NET 8 and .NET 9, run all supported targets, and verify packaged analyzers and trimming/NativeAOT diagnostics on each target. The analyzer package check explicitly loops over consumer frameworks; multi-target solution builds and tests are handled by MSBuild. Disable CheckEolTargetFramework within the migration package and each isolated verification consumer so newer SDKs do not reject the retained targets after their support end dates. The package-level props import the repository defaults; other packages retain their existing policy.

Validation:

  • Release solution build: zero warnings/errors. NuGet package validation and documentation snippet verification passed.
  • After the end-of-support property change, the Release solution build remained warning-free. Simulated SDK end-of-support checks passed for .NET 8/9 package projects and all four generated consumer templates; controls with CheckEolTargetFramework=true failed with NETSDK1138. Verified that all package projects still inherit repository defaults.
  • Runtime tests: 395 each on .NET 8/9/10, 513 on .NET 11.
  • Analyzer tests: 144 each on .NET 8/9/10 and 174 on .NET 11; sample tests: 44 each on .NET 8/9/10 and 49 on .NET 11. All passed.
  • A package consumer built and ran successfully with .NET SDK 8.0.319 using JSON 8.
  • Packed analyzer consumers passed on all four targets, including diagnostic severity checks. Untrimmed consumers ran, trimmed publish diagnostics passed, and NativeAOT compilation diagnostics passed. Local Windows AOT validation omitted native linking; the existing Linux CI path runs full publish.
  • Civil 3D 2025 Core Console, .NET 8.0.29: loaded pvsite first, then a consumer of the packed net8.0 asset. Static migration, tracking, current-model round trip, collection routing, and source-generated deserialization passed using System.Text.Json 8.0.0.0 in the default load context. A pvsite configuration containing scalars, a collection, and enum values round-tripped before and after loading the library. The control consumer requiring JSON 10 failed to bind. This is a host smoke test, not a full Civil 3D UI or grading regression test.

Other packages are unaffected: they do not reference the migration library, and this change does not edit their targets, workflows, central dependency versions, or shared build settings.

Copilot AI balanced review requested due to automatic review settings October 2, 2026 23:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The .NET 8 resolver test no longer exercises its named cycle scenario, and compatibility documentation remains contradictory.

Review effort: Balanced
Findings: 1 Medium severity · 2 Low severity

Open (3)
What changed in this PR

Adds a .NET 8 package asset without requiring a newer System.Text.Json, while retaining .NET 10/11 behavior.

Changes:

  • Multi-targets library, tests, samples, and benchmarks for .NET 8.
  • Accesses internal .NET 8 collection metadata for routing compatibility.
  • Expands routing tests, CI, analyzer, trimming, and NativeAOT validation.
File Description
.github/​workflows/​egil-systemtextjson-migration-ci.yml Adds .NET 8 CI coverage.
Egil.SystemTextJson.Migration/​AGENTS.md Documents supported frameworks.
Egil.SystemTextJson.Migration/​README.md Announces .NET 8 support.
Egil.SystemTextJson.Migration/​docs/​recipes/​aot-source-gen.md Documents the .NET 8 resolver workaround.
Egil.SystemTextJson.Migration/​perf/​Egil.SystemTextJson.Migration.PerfTests/​Egil.SystemTextJson.Migration.PerfTests.csproj Adds the .NET 8 benchmark target.
Egil.SystemTextJson.Migration/​samples/​Egil.SystemTextJson.Migration.Samples/​Egil.SystemTextJson.Migration.Samples.csproj Adds the .NET 8 sample target.
Egil.SystemTextJson.Migration/​scripts/​verify-analyzer-package.ps1 Parameterizes analyzer verification by framework.
Egil.SystemTextJson.Migration/​scripts/​verify-trimming-package.ps1 Verifies all three framework assets.
Egil.SystemTextJson.Migration/​src/​Egil.SystemTextJson.Migration/​Egil.SystemTextJson.Migration.csproj Adds the .NET 8 package asset.
Egil.SystemTextJson.Migration/​src/​Egil.SystemTextJson.Migration/​Migrations/​SourceValueShape.cs Uses the compatibility accessor on .NET 8.
Egil.SystemTextJson.Migration/​src/​Egil.SystemTextJson.Migration/​Migrations/​StjInternals.cs Adds access to internal collection metadata.
Egil.SystemTextJson.Migration/​test/​Egil.SystemTextJson.Migration.Analyzers.Tests/​Egil.SystemTextJson.Migration.Analyzers.Tests.csproj Runs analyzer tests on .NET 8.
Egil.SystemTextJson.Migration/​test/​Egil.SystemTextJson.Migration.Tests/​CollectionContractCompatibilityTests.cs Adds collection-routing compatibility coverage.
Egil.SystemTextJson.Migration/​test/​Egil.SystemTextJson.Migration.Tests/​Egil.SystemTextJson.Migration.Tests.csproj Runs runtime tests on .NET 8.
Egil.SystemTextJson.Migration/​test/​Egil.SystemTextJson.Migration.Tests/​ResolverChainTests.cs Adapts resolver setup for .NET 8.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread Egil.SystemTextJson.Migration/README.md Outdated
@LiteracyFanatic
LiteracyFanatic marked this pull request as draft October 3, 2026 00:07
Comment thread .github/workflows/egil-systemtextjson-migration-ci.yml Outdated
@LiteracyFanatic LiteracyFanatic changed the title feat(stjm): support .NET 8 without upgrading System.Text.Json feat(stjm): support .NET 8 and .NET 9 without upgrading System.Text.Json Oct 3, 2026
@LiteracyFanatic
LiteracyFanatic force-pushed the codex/stjm-net8-support branch from 5d90e7b to e593fc1 Compare October 3, 2026 03:25
@LiteracyFanatic LiteracyFanatic changed the title feat(stjm): support .NET 8 and .NET 9 without upgrading System.Text.Json feat(stjm): support .NET 8 and .NET 9 without JSON upgrades Oct 3, 2026

@egil egil left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One CI concern: out-of-support warnings for net8.0/net9.0 after .NET 11 GA. Suggested fix inline. The library changes look correct.


Generated by Claude Code

dotnet pack ./src/Egil.SystemTextJson.Migration/Egil.SystemTextJson.Migration.csproj -c Release --no-build --output ${{ env.NuGetDirectory }}
pwsh -NoProfile -File ./scripts/verify-analyzer-package.ps1 -PackagePath "$(find ${{ env.NuGetDirectory }} -maxdepth 1 -name '*.nupkg' -print -quit)"
# setup-dotnet installs SDKs in this job; this script verifies one target per call.
for framework in net8.0 net9.0 net10.0 net11.0; do

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI will likely break when .NET 8 and 9 go out of support (2026-11-10, same day as .NET 11 GA).

  • After the SDK pin moves to 11.0.x (per the workflow comment), global.json rolls forward to that SDK.
  • It will likely emit NETSDK1138 (target framework out of support) for net8.0 and net9.0.
  • This loop builds the consumers with -warnaserror, and Release builds set TreatWarningsAsErrors in the root Directory.Build.props, so that warning becomes an error. SDK 9.0.100 did the same to net6.0 on its release day.

Suggested fix: opt out of the check with the documented CheckEolTargetFramework property. It states intent better than adding NETSDK1138 to NoWarn.

  1. Library/test/perf/sample projects: add it to the root Directory.Build.props (or to a package-level one, if you'd rather keep it scoped to this package):
    <PropertyGroup Label="Compile settings">
      <!-- Deliberately keep targeting out-of-support TFMs (net8.0, net9.0). -->
      <CheckEolTargetFramework>false</CheckEolTargetFramework>
    </PropertyGroup>
  2. Generated consumer projects: these don't pick up the repo props. verify-analyzer-package.ps1 writes them to a temp dir, and verify-trimming-package.ps1 stubs out Directory.Build.props. So add the property inline to each generated <PropertyGroup>: Consumer.csproj, InvalidConsumer.csproj and SeverityConsumer.csproj in verify-analyzer-package.ps1, plus the trimming consumer in verify-trimming-package.ps1:
    <CheckEolTargetFramework>false</CheckEolTargetFramework>
    (Alternative: pass -p:CheckEolTargetFramework=false to each dotnet restore/build/publish call in the scripts.)

Generated by Claude Code

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added CheckEolTargetFramework=false in package-level Directory.Build.props, which explicitly imports the root props so existing build settings remain intact. It is also inline in all three analyzer consumer projects and the trimming/AOT consumer project. Other packages retain their existing SDK support checks.

The Release solution build passed on all four targets with zero warnings/errors. I simulated SDK end-of-support checks for .NET 8/9 across the package projects and all four generated consumer templates: the new settings passed, while controls with CheckEolTargetFramework=true failed with NETSDK1138.

Updated in 87b1f31; the PR still contains one commit.

Add .NET 8 and .NET 9 assets so applications and plugin hosts can
use migration support with their framework-provided System.Text.Json.
Read resolved collection metadata through a .NET 8-only accessor;
.NET 9 and newer retain the public API path.

Preserve collection-routing behavior and cover resolver snapshot
retention and cyclic discovery on the applicable runtimes. Keep
compatibility guidance consistent and extend CI and packed-consumer
verification across all supported targets without changing other
packages or shared dependency versions.

Keep the retained framework assets buildable with newer SDKs after
their support end dates by disabling framework end-of-support checks
within this package and its isolated verification consumers.
@LiteracyFanatic
LiteracyFanatic force-pushed the codex/stjm-net8-support branch from e593fc1 to 87b1f31 Compare October 3, 2026 19:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants