Dev.to WebDev 🛠 Dev 👁 0 📖 5 min read

Upgrading from .NET 8 to .NET 10: A Practical Checklist

Why upgrade now November 10, 2026 is the end-of-support date for both .NET 8 and .NET 9. Your apps keep running after that date, but they stop receiving security patches, so every new vulnerability stays open. The targ

Why upgrade now

November 10, 2026 is the end-of-support date for both .NET 8 and .NET 9. Your apps keep running after that date, but they stop receiving security patches, so every new vulnerability stays open. The target is .NET 10, the current LTS release, supported until November 2028 (Microsoft .NET Blog).

The good news: for most apps on modern .NET this is a days-long job, not a months-long one. The breaking changes are targeted and documented, and most of them show up as compiler warnings. This checklist is the order I'd follow for a typical solution, plus the changes most likely to bite.

Before you start

Take inventory first, retarget second. Ten minutes here saves hours of guessing later.

  1. List every deployable project, test project and shared library in the solution.
  2. Find every place a version is pinned: global.json, Dockerfiles, CI pipeline SDK versions, build scripts.
  3. Check what your machine and pipeline actually resolve:
dotnet --list-sdks
dotnet --info
  1. Check your dependencies for outdated or abandoned packages:
dotnet list package --outdated
  1. Run your test suite on the current version and save the result. You want a known-good baseline to compare against.
  2. Create a dedicated branch. Keep the SDK bump, the package updates and the code fixes in separate commits so a failure is easy to locate.

The upgrade, step by step

1. Pin the SDK. Install the .NET 10 SDK and update global.json:

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

2. Change the target framework in every project (or once in Directory.Build.props if you centralize it):

<TargetFramework>net10.0</TargetFramework>

Upgrade shared libraries first, then the apps that depend on them. If other teams consume your libraries, multi-target for a while with <TargetFrameworks>net8.0;net10.0</TargetFrameworks>.

3. Update Microsoft packages to 10.0.x. That means Microsoft.AspNetCore.*, Microsoft.Extensions.* and Microsoft.EntityFrameworkCore.*. Keep their versions aligned with each other.

4. Restore and read the new warnings. dotnet restore now audits transitive packages by default, so expect vulnerability warnings you didn't see before. NuGet also flags direct references it can prune (NU1510), and a PackageReference without a version is now an error.

5. Build with warnings as errors. Obsolete APIs surface as SYSLIB and ASPDEPR diagnostics. This is the fastest way to find most of what needs fixing:

dotnet build -warnaserror

6. Run the tests and the app. Compare against your baseline. Many changes are behavioral, so a green build is not the finish line: run integration tests with real configuration and real payloads.

What actually breaks

Coming from .NET 8 you inherit the breaking changes of both .NET 9 and .NET 10. These are the ones most likely to affect a typical web app; the full lists are linked in Sources.

Area Change What to do
ASP.NET Core WebHostBuilder, IWebHost and WebHost are obsolete Move to WebApplication.CreateBuilder or the generic host
ASP.NET Core IActionContextAccessor / ActionContextAccessor are obsolete Use IHttpContextAccessor instead
ASP.NET Core WithOpenApi() extension method is deprecated Remove it; the built-in generator now emits OpenAPI 3.1 by default. Pin 3.0 if your client generators need it
ASP.NET Core Razor runtime compilation is obsolete Rely on build-time compilation and Hot Reload
ASP.NET Core ForwardedHeadersOptions.KnownNetworks and IPNetwork are obsolete Switch to KnownIpNetworks with System.Net.IPNetwork
ASP.NET Core Cookie login redirects are disabled for known API endpoints API calls now get 401/403 instead of a redirect; check clients that expected the redirect
Blazor Response streaming is on by default for HttpClient in the browser Opt out per request if code reads the whole body synchronously
JSON Patch Now based on System.Text.Json instead of Newtonsoft Install the new package; avoid dynamic types like ExpandoObject
EF Core 10 ExecuteUpdateAsync takes a regular lambda Rewrite hand-built expression trees as plain lambdas
EF Core 10 EF tools need --framework on multi-targeted projects Add --framework net10.0 to dotnet ef commands while you multi-target
C# 14 field is a keyword inside property accessors Rename members called field or use @field
C# 14 Span overloads apply in more places Fix new ambiguity errors with an explicit cast
Runtime No default SIGTERM handler is installed Add your own if you relied on it for graceful shutdown
Extensions BackgroundService runs all of ExecuteAsync as a Task Synchronous startup code in ExecuteAsync no longer blocks host startup
Containers Default images use Ubuntu instead of Debian Fix Dockerfiles that use Debian package names or paths

CI/CD and Docker

The code is only half the upgrade; the pipeline still builds with whatever SDK it was told to use.

GitHub Actions:

- uses: actions/setup-dotnet@v4
  with:
    dotnet-version: '10.0.x'

Azure DevOps:

- task: UseDotNet@2
  inputs:
    packageType: 'sdk'
    version: '10.0.x'

Dockerfile: bump both stages and remember the new Ubuntu base:

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

If your Dockerfile installs packages with apt-get, check the package names still exist on Ubuntu. In automated scripts, pass --interactive false to CLI commands, since the CLI now defaults to interactive mode for users.

Coming from .NET Framework

A .NET Framework 4.x app is a migration, not a version bump. .NET Framework 4.8 is not part of the November 2026 deadline, since its support follows the Windows lifecycle, but staying on it means no new runtime features and a shrinking library ecosystem.

What changes:

  • Project files. Convert old-style .csproj files to SDK-style, and packages.config to PackageReference.
  • Configuration. web.config / app.config settings move to appsettings.json and the options pattern.
  • Hosting and startup. Global.asax and System.Web are gone; the pipeline is built in Program.cs with middleware.
  • Dependency injection is built in, so third-party containers become optional.
  • No direct path for some technologies. ASP.NET Web Forms, WCF server and Windows Workflow have no direct equivalent and need a partial rewrite (for example Razor Pages or Blazor for Web Forms, CoreWCF or gRPC for WCF).

The usual approach: move class libraries to .NET Standard 2.0 or multi-target them first, then migrate the web project, then remove the old one. For large apps, migrate incrementally route by route behind a reverse proxy instead of a big-bang rewrite.

The short checklist

  • Inventory projects, pinned SDKs, Dockerfiles and pipelines
  • Baseline test run on the current version
  • global.json pinned to the .NET 10 SDK
  • All projects on net10.0, shared libraries first
  • Microsoft packages on 10.0.x, versions aligned
  • New NuGet audit warnings reviewed
  • Build clean with -warnaserror
  • Breaking changes from .NET 9 and .NET 10 reviewed
  • CI/CD and Docker images on 10.0
  • Tests and integration tests green, compared to baseline

Free tool: scan your solution first

To get the inventory from the first step in one command, I wrote a free, open-source PowerShell script: NetUpgradeLab Scanner. It's read-only and produces a Markdown report of projects, outdated Microsoft packages, obsolete APIs and pinned SDK/Docker/CI versions.

pwsh ./Invoke-NetUpgradeScan.ps1 -Path C:\src\MySolution

Need a hand?

I'm Jasmin, a .NET developer with 6+ years of experience in C#, ASP.NET Core, Blazor and SQL Server. If you'd rather hand the upgrade off, I take on .NET 10 upgrades and .NET Framework migrations: Upgrade your app to .NET 10.

Sources

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.