A migration strategy built for live enterprise systems
The source project had around 150 projects, multiple back-end applications, shared libraries, console tools, and an actively used product. In that situation, a big-bang rewrite creates too much delivery and business risk.
The practical answer is to turn the migration into a sequence of focused tickets: modernize the build setup first, move shared libraries into a compatibility target, then migrate the applications and hosting model once the foundations are ready.
.NET Standard 2.0 is the bridge, not the destination
It allows .NET Framework 4.8 and .NET 6 to consume the same library during the transition. That compatibility is what makes an iterative migration feasible. Once the whole solution is modernized, move those libraries to .NET 6 as well.
Projects
A large solution with several application types and many dependencies.
Big-bang rewrites
Keep delivery moving by slicing the migration into independent steps.
Bridge target
Shared code can serve both the old and the modern runtime during the rollout.
What .NET Framework, .NET, and .NET Standard actually mean
Getting these three terms right makes the rest of the migration plan far easier to reason about.
.NET Framework 4.8
The classic Windows-only runtime. It is still supported, but it is not the future-facing, cross-platform runtime for new development.
.NET 6
The modern, cross-platform runtime that continues the path started by .NET Core. This is the direction for new workloads and long-term evolution.
.NET Standard
Not a runtime, but an API contract. If both sides implement that contract, the same library can run on .NET Framework 4.8 and on .NET 6.
interface ITask
{
void Execute();
}
class NetFramework48 : ITask
{
}
class Net6 : ITask
{
}Use .NET Standard 2.0 to reduce migration coupling
Microsoft still supports .NET Standard 2.0, and both .NET Framework 4.8 and .NET 6 implement it. That makes it ideal for shared libraries during a transition. The important nuance is that you should treat it as a temporary compatibility layer, not the final architecture.
A pragmatic phased migration path
Do the work in an order that creates options instead of dragging legacy assumptions deeper into the codebase.
Start with groundwork
Move projects to SDK-style csproj files, replace packages.config, and review NuGet compatibility early. Tools like Upgrade Assistant can remove a lot of manual work.
Migrate isolated console apps first
Standalone executables with few dependencies can often move directly from net48 to net6.0. They are useful for building confidence and exposing easy wins.
Move shared libraries to .NET Standard 2.0
This is the key bridge step. Shared code becomes consumable by both .NET Framework 4.8 and .NET 6 applications while the rest of the solution is still mixed.
Bridge runtime-specific dependencies
Before migrating the heavier applications, remove Framework-specific assumptions from shared code. Replace things like HttpContext.Current with abstractions that can survive the mixed-runtime period.
Move tests, Web APIs, and services
Once shared code is ready, migrate unit tests onto a real runtime, move Web API to ASP.NET Core, and replace older Windows service hosting approaches like TopShelf.
Finish by moving bridge libraries to .NET 6
When the solution runs fully on modern runtimes, retire netstandard2.0, move libraries to net6.0, and then modernize architecture and platform choices from a stable baseline.
The parts that deserve explicit planning
Changing the target framework is the easy diff. Most of the real work lives at runtime boundaries, hosting assumptions, and older infrastructure choices.
HttpContext.Current disappears
Old shared libraries often depend on HttpContext.Current. In an iterative migration, replace that access with abstractions like IHttpContextAccessor so both worlds can be supported during the transition.
ASP.NET Web API moves differently
Global.asax, WebApiConfig, and request lifecycle hooks do not map one-to-one. A clean ASP.NET Core project plus explicit Program.cs and middleware migration is usually the safer path.
TopShelf needs a new hosting model
If Windows services rely on TopShelf, plan a move to BackgroundService and the modern hosting model. This is more than a target framework change.
SignalR can force frontend work
Old and new SignalR stacks are not interchangeable. Backend migration can require coordinated frontend changes, so track that dependency early.
JSON defaults may change behavior
ASP.NET Core defaults to System.Text.Json, while older applications often rely on Newtonsoft.Json settings. If serialization behavior matters, migrate that intentionally rather than by accident.
IIS, auth, and model binding are stricter
Modern .NET on IIS often needs the hosting bundle, explicit Negotiate/IIS authentication setup, and closer attention to payload shapes because model binding and serialization are less permissive than older Framework behavior.
Keep the migration focused
First land the platform migration safely. Then, from a stable baseline, modernize dependency injection, serializers, architecture, or hosting choices without mixing every refactor into the same move.
Let's talk about your project
Let's Build Something Great Together
Have a question or want to discuss a project? We'd love to hear from you. Fill out the form below and we'll get back to you as soon as possible.
You can also reach us directly at [email protected]