Skip to content

feat: add .NET 11 support and drop .NET 8 and .NET 9 - #5529

Draft
jamescrosswell wants to merge 6 commits into
version7from
net11-preview7
Draft

feat: add .NET 11 support and drop .NET 8 and .NET 9#5529
jamescrosswell wants to merge 6 commits into
version7from
net11-preview7

Conversation

@jamescrosswell

@jamescrosswell jamescrosswell commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Gets the SDK building and testing against .NET 11 preview 7, targeting version7.

Closes #5527

TFMs

net11.0 becomes the latest TFM and net10.0 the previous; net8.0 and net9.0 are dropped (both lose LTS when .NET 11 ships). Platform TFMs follow the preview 7 workload set (11.0.100-preview.7.26410.2):

Latest Previous
base net11.0 net10.0
android net11.0-android37.0 net10.0-android36.0
ios net11.0-ios26.5 net10.0-ios26
maccatalyst net11.0-maccatalyst26.5 net10.0-maccatalyst26
windows net11.0-windows10.0.19041.0 net10.0-windows10.0.19041.0

iOS and MacCatalyst only publish a net11.0_26.5 ref pack, so those need the minor version — unlike the current net10.0-ios26.

Samples are bumped by hand rather than moved onto the central properties: they're documentation, and $(LatestTfm) doesn't resolve outside this repo.

What .NET 11 actually changed

  • Mono is gone for Android (NETSDK1242). RunAOTCompilation is Mono-only, so Mono-AOT APKs cannot be produced at all. The APK matrix in Sentry.Android.AssemblyReader.Tests builds the AOT variants for net10.0-android only.
  • The Cocoa bindings are nullable-annotated. This surfaced a latent bug: GetBundleValue did NSBundle.MainBundle.ObjectForInfoDictionary(key).ToString(), so a missing Info.plist key would have thrown while building the release/distribution string. NSObject.FromObject is also nullable now, and two conversions were storing its result straight into a Dictionary<NSString, NSObject>.
  • Minimum deployment targets rose: Android API 21 → 24, MacCatalyst 15.0 → 17.0. Both are applied to the net11.0 TFM only, so net10.0 consumers are unaffected. Android API 24 is a user-facing breaking change for .NET 11 — it drops Android 5.0, 5.1 and 6.0 — and wants a line in the 7.0.0 breaking changes.
  • The synchronous HttpClient.Send is annotated unsupported on iOS/MacCatalyst. Suppressed narrowly in the test helper, whose callers all supply a substitute inner handler.
  • MAUI 11's MSIX PRI expansion shells out to makepri.exe, so cross-building net11.0-windows from macOS/Linux fails. net10.0-windows is fine, so this is new. PRI expansion is skipped when the host isn't Windows; Windows CI still runs the full path.
  • Convert.FromBase64String now routes through System.Buffers.Text.Base64, changing the declaring type of the top stack frame. DebugStackTraceTests was asserting one specific type in a sanity check; it now checks the namespace, which is what InApp actually keys off.

A recurring trap worth knowing: several ItemGroups are keyed on TargetFrameworkVersion == 'v10.0', and a new TFM silently gets no packages at all rather than an error. Seven of them needed a v11.0 sibling — this is what produced the Sentry.Bindings.Android XA4242 Java-dependency failures.

Known gaps

  • Android assembly store v4 is unsupported, so there is no Android symbolication on .NET 11. .NET 11 emits store format v4 (observed header 0x80030004), and v4 changed the header/index layout as well as the version number — adding the version alone gets past IsSupported() and then fails in Prepare(). This is already tracked in Port upstream AssemblyStore reader changes: v4/CoreCLR format, _assembly_store symbol, index-entry sizing (next major) #5454, which identifies the same root cause (a new content_id header field when the format number is >= 4). It degrades gracefully: AndroidHelpers.GetAndroidAssemblyReader catches, logs and returns null. 20 tests in AndroidAssemblyReaderTests are skipped on net11.0 with a reason pointing at Port upstream AssemblyStore reader changes: v4/CoreCLR format, _assembly_store symbol, index-entry sizing (next major) #5454, and must be re-enabled when that port lands. net10.0 still runs all 23.
  • Sentry.Samples.OpenTelemetry.AzureFunctions stays on net10.0. The Azure Functions Worker SDK has no .NET 11 support — 2.0.7 and the current 2.1.0 both reject the TFM with "Invalid combination of TargetFramework and AzureFunctionsVersion is set."
  • Microsoft.CodeAnalysis.Testing ships no ReferenceAssemblies.Net.Net110 (1.1.4 stops at Net100), so Sentry.Compiler.Extensions.Tests declares one locally, pinned to Microsoft.NETCore.App.Ref 11.0.0-preview.7.26381.103. Keep it in step with global.json.

Local verification

macOS, .NET 11 preview 7 SDK with the preview 7 workload set:

  • dotnet build Sentry-CI-Build-macOS.slnf -c Release0 errors, 37 warnings
  • dotnet test Sentry-CI-Build-macOS.slnf -c Release7201 passed, 0 failed, 74 skipped across 41 test assemblies, covering both net10.0 and net11.0 plus the android/ios/maccatalyst TFMs

Depends on #5528

nuget.config maps the perfview-build feed to the * package pattern, so NuGet queries it for every package and its anonymous upstream proxy answers 401 for anything it hasn't cached. That currently breaks restore for the .NET 11 packages (and is why main is red). The fix is #5528 against main; this branch will not restore in CI until that lands and main is merged into version7.

Notes

  • The net11.0 verified snapshots are byte-identical to their net10.0 counterparts. The net48 ones can only be produced on Windows, so verify-api will commit those.
  • integration-test/net9-maui is renamed to maui-app — it's a generic MAUI template and the version in the name has now aged twice.
  • Six stale DotNet6_0/DotNet7_0 snapshots predate this work (left behind by cb0a35c) and are untouched here.

Shifts the centralized TFM properties up one release: net11.0 becomes the
latest TFM and net10.0 the previous, dropping net8.0 and net9.0 (both lose
LTS when .NET 11 ships in November).

Platform TFMs follow the preview 7 workload set (11.0.100-preview.7.26410.2):
android 37.0.0-preview.7.2131, iOS/MacCatalyst/macOS 26.5.11997-net11-p7.
Note iOS and MacCatalyst only ship a net11.0_26.5 ref pack, so those TFMs
need the minor version, unlike the current net10.0-ios26.

Samples are bumped by hand rather than moved onto the central properties -
they are documentation for SDK users and stay conventional and literal.
Pins global.json to the preview 7 SDK and its workload set, and updates the
projects that don't consume the centralized TFM properties:

- Sentry.Maui.CommunityToolkit.Mvvm (+ tests) and Sentry.MauiTrimTest were
  pinned to exactly the Previous* TFM set, so they now use those properties
  and will track future bumps on their own.
- SingleFileTestApp and Sentry.TrimTest move to net11.0, so single-file
  bundle reading and trim/AOT analysis are exercised against the new runtime.
- The TFM switches in SingleFileAppTests and AndroidAssemblyReaderTests, and
  the APK build matrix in Sentry.Android.AssemblyReader.Tests, gain net11.0
  and drop net9.0/net8.0.
Works through what building against .NET 11 preview 7 surfaced:

- Android raised its minimum deployment target to API 24 and MacCatalyst to
  17.0. Both are applied only to the net11.0 TFM, so net10.0 consumers keep
  API 21 / 15.0. Raising Android's floor is user-facing: it drops Android
  5.0-6.0 for net11.0.
- Seven ItemGroups keyed on TargetFrameworkVersion v10.0 had no v11.0 sibling,
  leaving the new TFM with no packages at all. This is what produced the
  Sentry.Bindings.Android XA4242 Java dependency failures - the AndroidX and
  Kotlin references simply weren't there for net11.0-android37.0.
- The Cocoa bindings are now nullable-annotated. ObjectForInfoDictionary and
  NSObject.FromObject return nullable values, which exposed a latent NRE when
  an Info.plist key is missing, and two spots that could store null in a
  non-nullable NSObject dictionary. The marshal-exception delegates also
  declare a nullable sender now.
- .NET 11 Android defaults to CoreCLR, and RunAOTCompilation is Mono-only, so
  the APK build matrix now asks for Mono only on the AOT cases.
- The synchronous HttpClient.Send is annotated unsupported on iOS/MacCatalyst;
  suppressed at the test helper, whose callers all use a substitute handler.
- integration-test/net9-maui is renamed to maui-app - it's a generic MAUI
  template, and pinning a .NET version in the name has aged badly once.

Sentry.Samples.OpenTelemetry.AzureFunctions stays on net10.0: the Azure
Functions Worker SDK has no .NET 11 support yet (2.0.7 and 2.1.0 both reject
the TFM). Sentry.Compiler.Extensions.Tests compiles its analyzer snippets
against the .NET 10 reference assemblies, as Microsoft.CodeAnalysis.Testing
ships nothing newer than Net100.
- .NET 11 removes the Mono runtime for Android (NETSDK1242), so Mono AOT
  cannot be produced at all. The AOT APK variants are now built only for
  net10.0-android. No coverage is lost: AndroidAssemblyReaderTests already
  skips every AOT case, so those APKs were built but never read.
- MAUI 11's MSIX PRI expansion shells out to the Windows-only makepri.exe,
  which breaks cross-building net11.0-windows from macOS. net10.0-windows is
  unaffected, so PRI expansion is skipped when the host isn't Windows.
- MauiEventsBinderTests had no live branch left once net9 went, leaving
  navigatedToEventArgs undeclared on every TFM; the conditional is gone.
- LocalDbFixture gains its net11.0 name, and drops arms for TFMs we no longer
  build. Its #else is a hard #error - each TFM needs a distinct database name.
- The MAUI sample carried unused Frame and ListView styles from the project
  template, both obsolete in MAUI 11, and one EndAndExpand layout option.
- BL0012 is suppressed in the Blazor sample: the analyzer treats
  StateHasChanged as redundant after an event handler, but that handler always
  throws, so the automatic re-render never runs.

Drops the net8.0 and net9.0 verified snapshots. The net11.0 ones regenerate
themselves on a test run, and CI's Windows job produces the net48 files.
…ader tests

- ReferenceAssembliesExtensions declares a real net11.0 entry. Falling back to
  Net100 did not work: the analyzer snippets reference a net11.0-built
  Sentry.dll, so CS1705 fires against .NET 10 reference assemblies.
  Microsoft.CodeAnalysis.Testing has its own PackageIdentity, so this needs no
  extra package reference.
- DebugStackTraceTests asserted the top frame's declaring type was exactly
  System.Convert. .NET 11 routes Convert.FromBase64String through
  System.Buffers.Text.Base64. That was only the test's sanity check - what it
  actually asserts is keyed off the namespace, so it now checks that instead.
- AndroidAssemblyReaderTests skips the AOT permutations on net11.0. The
  existing Skip.If(isAot) is inside #if ANDROID, so on host runs every
  permutation executes and needs an APK - and .NET 11 cannot produce Mono-AOT
  APKs at all.
- StoreReader documents that .NET 11 emits assembly store v4, which changes the
  header/index layout and not just the version number. Bumping the constant
  alone gets past IsSupported() and then fails in Prepare().
Generated by a local test run. Content is byte-identical to the net10.0
snapshots in every case, so .NET 11 introduces no behavioural difference
here - Verify just keys these files by target framework.

The net48 snapshots can only be produced on Windows, so CI's verify-api job
will commit those.
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.

1 participant