How I Upgraded a Legacy .NET Core 3.1 Project to .NET 8—With Minimal Pain

VaibhavVaibhav
4 min read

Upgrading a legacy application sounds exciting until you realize how many things can break. I recently led the migration of a production .NET Core 3.1 application to .NET 8, and it turned out to be smoother than expected, thanks to a disciplined approach and some hard-earned lessons.

In this article, I’ll walk you through:

  • Why we upgraded

  • The challenges we faced

  • A step-by-step upgrade strategy

  • Best practices and tooling

  • Real code examples


✨ Why Upgrade from .NET Core 3.1 to .NET 8?

.NET 8 brings several compelling improvements:

  • Long-Term Support (LTS)

  • Better performance and memory management

  • Minimal APIs and cleaner hosting model

  • Unified platform across workloads

.NET Core 3.1 reached end of support, so staying on it posed a security and maintenance risk.


⚠️ Key Challenges We Encountered

  1. Third-party NuGet packages were outdated or deprecated

  2. Incompatible ASP.NET Core middleware or APIs

  3. Breaking changes in EF Core and project SDKs

  4. Custom MSBuild tasks failing due to SDK changes

  5. CI/CD pipeline adjustments for new SDKs and runtime


📆 Step-by-Step Upgrade Process

1. Inventory All Projects and Dependencies

  • List all class libraries, web apps, test projects

  • Check their dependencies (.NET version, NuGet packages)

  • Use tools like dotnet list reference or dotnet-project-graph to understand how projects are linked

  • Consider using dependency visualization tools (e.g., NDepend or Project Dependency Viewer in Visual Studio) to identify tight coupling or unnecessary references

  • List all class libraries, web apps, test projects

  • Check their dependencies (.NET version, NuGet packages)

2. Update SDKs and Target Frameworks

<TargetFramework>net8.0</TargetFramework>
  • Also update global.json if used

  • Use dotnet --list-sdks to verify the .NET 8 SDK is installed on your system

  • Be aware that global.json may force your build to use an older SDK; ensure it aligns with the version you're upgrading to

<TargetFramework>net8.0</TargetFramework>
  • Also update global.json if used

3. Refactor Startup and Program Files

From:

public class Startup
{
    public void ConfigureServices(IServiceCollection services) { }
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { }
}

To:

var builder = WebApplication.CreateBuilder(args);

// Register services
builder.Services.AddControllers();

var app = builder.Build();

// Configure middleware
app.UseRouting();
app.UseAuthorization();
app.MapControllers();

app.Run();

This shift from Startup.cs to the minimal hosting model is a major architectural change in .NET 6 and later. You need to:

  • Move ConfigureServices logic into builder.Services

  • Transfer all Configure middleware logic (e.g., UseRouting, UseAuthentication, UseAuthorization, etc.) into the new middleware pipeline before app.Run()

  • Ensure custom middlewares and service registrations (like Swagger, CORS, logging) are manually migrated From:

public class Startup
{
    public void ConfigureServices(IServiceCollection services) { }
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { }
}

To:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapControllers();
app.Run();

4. Replace or Upgrade Deprecated Packages

  • Use dotnet list package --outdated

  • Replace unsupported libraries (e.g., logging, auth, UI components)

5. Handle Breaking Changes in EF Core

  • Re-run migrations using the latest EF Core CLI commands

  • Carefully review the official EF Core 8 breaking changes documentation

  • Pay attention to changes in behavior for methods like AsNoTracking(), Include(), and transaction handling

  • EF Core 8 has performance improvements that may require tuning or testing your LINQ queries

  • Consider using EF Core Power Tools to reverse engineer or visually analyze your DbContext and model mappings

  • Review your database providers and ensure they are fully compatible with EF Core 8

  • Re-run migrations

  • Check for AsNoTracking() and other method behavior changes

6. Update Unit Tests and Mocks

  • Update test projects to target .NET 8

  • Replace deprecated test libraries

7. Revise CI/CD Pipeline and Docker Files

  • Use .NET 8 SDK base images
FROM mcr.microsoft.com/dotnet/aspnet:8.0
  • Update build agents and runtime checks in your CI pipeline

For Azure DevOps:

  • Update azure-pipelines.yml to use windows-latest or ubuntu-latest agents with .NET 8 installed

  • Add a UseDotNet@2 task to install .NET 8 SDK if needed

For GitHub Actions:

  • Ensure actions/setup-dotnet@v3 specifies dotnet-version: '8.x'
- uses: actions/setup-dotnet@v3
  with:
    dotnet-version: '8.x'

For GitLab CI:

  • Update image: to use a .NET 8 compatible Docker image

  • Add .NET restore, build, and test steps with updated SDK paths

Ensure Dockerfiles and CI runners match your upgraded framework version to prevent runtime conflicts.

  • Use .NET 8 SDK base images
FROM mcr.microsoft.com/dotnet/aspnet:8.0
  • Update build agents and runtime checks

8. Smoke Test Everything

  • Local testing

  • CI automation

  • Staging environment validation


🔧 Tools That Helped

  • Upgrade Assistant: dotnet tool install -g upgrade-assistant

  • .NET Portability Analyzer

  • SonarQube / Resharper for code quality and cleanup

  • NuKeeper / Renovate for dependency versioning


💼 Best Practices

  • Upgrade library projects before applications

  • Use separate branches to isolate upgrade work

  • Freeze feature development during the upgrade

  • Communicate the changes to QA/DevOps early

  • Monitor production logs post-deployment


🔍 Final Thoughts

The move from .NET Core 3.1 to .NET 8 is more than a version bump, it’s an opportunity to modernize and clean up your codebase. If done thoughtfully, you can future-proof your application without introducing chaos.

If you’re planning your upgrade soon: start small, test often, and document everything.

Happy upgrading!

0
Subscribe to my newsletter

Read articles from Vaibhav directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Vaibhav
Vaibhav

I break down complex software concepts into actionable blog posts. Writing about cloud, code, architecture, and everything in between.