Skip to main content

Migrating to .NET 10 Only

As of Sprint 797 (April 2026), Excalibur.Dispatch targets .NET 10.0 exclusively. Every shipping NuGet package (Dispatch core, Excalibur domain/event-sourcing, transports, hosting providers, compliance, samples, and templates) dropped net8.0 and net9.0 from <TargetFrameworks> in a single sprint.

This page is forward-looking guidance for consumers. For the sprint's architectural rationale see ADR-108 (.NET 10 multi-targeting) and the Sprint 797 review.

What changed

  • Target framework: <TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks><TargetFramework>net10.0</TargetFramework> across every shipping project.
  • Dependencies refreshed: Microsoft.Extensions.*10.0.6, Azure.Functions.Worker2.51.0, OpenTelemetry1.15.2, Polly8.6.6, Elastic.Transport → 0.10.1, Elasticsearch client → 8.17.0, plus the AWS/Azure/GCP SDK families.
  • Preprocessor cleanup: 705 deletions of dead #if NET8_0 / #if NET9_0 branches. IsExternalInit.cs in Excalibur.Dispatch.SourceGenerators retains its #if NETSTANDARD2_0 polyfill because Roslyn source generators must target netstandard2.0 for compatibility with the Roslyn SDK — this is TFM polyfill, not feature gating.
  • PublicAPI baselines: Per-TFM PublicAPI.Shipped.txt variance removed. Each shipping package now owns a single baseline.
  • CI shard matrix: 10 shards execute once per build instead of once per TFM. Per-TFM shard multipliers retired.
  • Azure Functions Worker: Upgraded to v2 SDK. FunctionContextProxy now matches the abstract FunctionContext base per AzureFunctionsHostProvider contract.
  • Azure Key Vault: An internal ISecretClient seam was introduced in Excalibur.Security.Azure so tests can fake secret operations without reflection. Consumer APIs are unchanged; the seam is internal.

Why .NET 10 only

  1. .NET 9 STS lifecycle ends May 2026. Continuing to ship .NET 9 targets after end-of-support would leave consumers on an unsupported runtime for security patches.
  2. .NET 10 is the current LTS (November 2025 → November 2028). Framework-as-NuGet with single-target LTS aligns with Microsoft's own pattern for new libraries (Microsoft.Extensions.* 10.x, Azure.* SDKs).
  3. AOT and trimming gains. .NET 10 ships improvements to System.Text.Json source generators, trim analysis, System.Threading.Lock, and UTF-8 literals. Multi-targeting below .NET 10 blocked access to these.
  4. Greenfield invariant. The framework is pre-release with no shipped consumers. The migration window is architecturally optimal; breaking the TFM contract is free today and expensive later.

Required consumer changes

1. Update your project TFM

<!-- Before -->
<TargetFramework>net8.0</TargetFramework>

<!-- After -->
<TargetFramework>net10.0</TargetFramework>

If your project currently multi-targets (<TargetFrameworks>net8.0;net10.0</TargetFrameworks>), drop the net8.0 entry. Excalibur.Dispatch 10.x packages no longer ship net8.0 or net9.0 assets, so your net8.0 build will fail to resolve.

2. Install .NET 10 SDK

Install the .NET 10 SDK on every development machine and every CI runner. Update global.json if present:

{
"sdk": {
"version": "10.0.100",
"rollForward": "latestFeature"
}
}

Update Docker base images:

# Before
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime

# After
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime

Update CI runner setup actions (actions/setup-dotnet and equivalents) to pin dotnet-version: 10.0.x.

3. Serverless runtime identifiers

PlatformOldNew
AWS Lambdadotnet8 / dotnet9dotnet10
Google Cloud Functionsdotnet9dotnet10
Azure FunctionsWorker v1 (Microsoft.Azure.Functions.Worker 1.x)Worker v2 (2.51.0+)

Project templates (dotnet new dispatch-api, dotnet new dispatch-worker, dotnet new dispatch-functions) generate .csproj and Dockerfiles against .NET 10 only. The --Framework option has been narrowed to net10.0.

If your project directly references any of the packages Dispatch also pulls in (for example, you register your own OpenTelemetry pipeline or configure Azure Functions Worker independently), align your versions with the Dispatch floor:

Package familyMinimum
Microsoft.Extensions.*10.0.6
Microsoft.Azure.Functions.Worker*2.51.0
Azure.Security.KeyVault.Secrets4.10.0
OpenTelemetry*1.15.2
Polly8.6.6
Elastic.Transport0.10.1
Elastic.Clients.Elasticsearch8.17.0

No public Excalibur.Dispatch API signatures changed as part of the dep refresh.

No code changes required

Sprint 797 was a targeting-and-dependency sprint, not a behavior sprint. No public API was added, removed, renamed, or resignatured. The Sprint 797 architect review verifies PublicAPI.Unshipped.txt is empty on every shipping project; no new public symbols were introduced by the AOT audit or the ISecretClient seam (the seam is internal).

Rollback

There is no rollback path within the 10.x release line. Consumers who cannot move to .NET 10 should pin to the last pre-S797 release and stay there. Because Sprint 797 lands before the framework's first stable release, no downstream consumers are pinned today.