Migrating from .NET Framework to Modern .NET: What to Expect
October 30, 2023
The decision to migrate from .NET Framework to .NET 8 is usually straightforward. The execution is where the complexity lives.
Most organizations underestimate migration scope because they focus on the application code and undercount the dependencies. The application code is often the fastest part. Third-party packages that haven't shipped .NET Core-compatible versions, Windows-specific APIs used in ways that don't have direct equivalents, Web.config-based configuration that's been used for environment-specific behavior over years — these are where migrations stall.
The dependency audit should happen before anything else. Not a cursory review, but an actual inventory of every NuGet package, every P/Invoke call, every COM interop, every reference to System.Web. The results of that audit determine whether the migration is a two-month effort or an eight-month one. Organizations that skip the audit tend to discover blockers mid-migration, after they've already committed to a timeline.
The Configuration Problem
Web.config in .NET Framework isn't just configuration — it's where years of environment-specific behavior has accumulated. Transforms for different environments, third-party library configuration sections, IIS-specific settings, application settings that have grown organically over the application's lifespan. Moving to appsettings.json and the .NET Core configuration system requires understanding what all of that configuration actually does, which is often more work than it sounds for applications with long histories.
The Global.asax equivalent is another category. Application startup logic, HTTP module configurations, custom error handling — these need to be mapped to the Startup.cs pattern (or Program.cs in minimal hosting), and the mapping isn't always one-to-one.
What Drives the Timeline
Simple applications with clean dependencies and no Windows-specific code can migrate in days. The applications that take months are the ones with meaningful Windows dependencies, extensive use of System.Web, large test surface areas, or deployment pipelines tightly coupled to IIS configuration assumptions.
The test coverage question matters more than most teams expect. A migration that touches the application's foundational infrastructure needs tests to verify that behavior hasn't changed. Applications with good coverage migrate with more confidence. Applications with minimal coverage require either accepting more risk or writing characterization tests before the migration starts — work that adds to the timeline but shouldn't be skipped.
The .NET Upgrade Assistant is useful for the mechanical parts of the migration — project file conversion, package updates, API surface changes with known equivalents. It doesn't replace the judgment work: deciding which architectural patterns to carry forward vs. improve, how to handle the configuration transition, where to accept temporary compatibility shims vs. rewriting for the new patterns.
Migrating because .NET Framework is in maintenance mode is the right reason. The security posture and performance improvements in modern .NET are real. The timeline just needs to be built against what the codebase actually contains.
Working through a problem like this?
Describe the system and where it's stuck. I'll tell you what the work actually involves.
Get in touch