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.
A distilled version of Steven Giesel's migration guide: align the terminology first, use .NET Standard 2.0 as the bridge, and move large systems in safe, iterative slices.
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.
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.
A large solution with several application types and many dependencies.
Keep delivery moving by slicing the migration into independent steps.
Shared code can serve both the old and the modern runtime during the rollout.
Getting these three terms right makes the rest of the migration plan far easier to reason about.
The classic Windows-only runtime. It is still supported, but it is not the future-facing, cross-platform runtime for new development.
The modern, cross-platform runtime that continues the path started by .NET Core. This is the direction for new workloads and long-term evolution.
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
{
}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.
Do the work in an order that creates options instead of dragging legacy assumptions deeper into the codebase.
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.
Standalone executables with few dependencies can often move directly from net48 to net6.0. They are useful for building confidence and exposing easy wins.
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.
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.
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.
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.
Changing the target framework is the easy diff. Most of the real work lives at runtime boundaries, hosting assumptions, and older infrastructure choices.
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.
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.
If Windows services rely on TopShelf, plan a move to BackgroundService and the modern hosting model. This is more than a target framework change.
Old and new SignalR stacks are not interchangeable. Backend migration can require coordinated frontend changes, so track that dependency early.
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.
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.
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 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.
Grüezi! Prefer to chat first? Let's grab a virtual coffee and explore how we can help bring your vision to life!
Schedule 30-Min Google MeetYou can also reach us directly at [email protected]