Many businesses run important systems on the .NET Framework: an ASP.NET Web Forms or MVC 5 portal, a WCF service, a Windows service that runs every night. They work, people depend on them, and nobody wants to touch them. But the .NET Framework is no longer where Microsoft's development happens. New performance improvements, language features, container support and cross-platform hosting all arrive in modern .NET.
The tempting answer is to rewrite everything. In our experience, that is usually the riskiest option. This article describes a steadier route.
Why big-bang rewrites go wrong
A full rewrite means building a second copy of a system while the first one keeps changing. The old system holds years of business rules that nobody wrote down: special cases for particular customers, workarounds for old data, behaviour users rely on without knowing it. A rewrite discovers these one at a time, often after go-live. Meanwhile, the business waits months or years for any benefit.
An incremental migration delivers value early, keeps the old system running as a safety net, and lets you stop or change direction at any point.
Step 1: Take an honest inventory
Before planning anything, list what you actually have:
- The application types: Web Forms, MVC, Web API, WCF, Windows services, desktop applications.
- The libraries and NuGet packages each project depends on, and whether they have modern .NET versions.
- Anything tied to Windows or to
System.Web, such as session state, the registry or COM components. - The database access approach, for example Entity Framework 6, plain ADO.NET or stored procedures.
- How the system is built, deployed and monitored today.
This tells you which parts will move easily and which need real work. Microsoft's upgrade tooling and API analysis can help, but the judgement about what matters to the business is yours.
Step 2: Put a safety net in place
Older systems often have few automated tests. Before changing anything, add tests that record what the system does today, especially around calculations, pricing, permissions and integrations. These tests are not about whether the behaviour is right. They tell you whether you have changed it by accident.
Step 3: Move the shared libraries first
Class libraries with business logic are usually the easiest place to start. Convert them to the modern SDK-style project format and, where possible, target .NET Standard 2.0 or multi-target both the old framework and modern .NET. The existing application keeps using them, and new code can use them too.
Step 4: Migrate the web application piece by piece
For web applications, the most reliable pattern is to put a new ASP.NET Core application in front of the old one. A reverse proxy such as YARP sends each request either to a page that has already been migrated or to the old application. Users see one website. Microsoft's System.Web adapters help the two applications share things like session and authentication during the transition. You move one area at a time, starting with something valuable but low-risk, until the old application handles nothing and can be switched off.
Step 5: Deal with the harder parts deliberately
- Web Forms has no direct equivalent in modern .NET. Its screens need to be rebuilt, for example in Razor Pages, MVC or Blazor. The incremental approach means you rebuild them one at a time.
- WCF services can move to CoreWCF if clients depend on the existing contracts, or to REST or gRPC if you control the clients.
- Entity Framework 6 runs on modern .NET, so data access does not have to change at the same time as everything else. Moving to EF Core can be a later step.
- Windows-only dependencies can stay on Windows for now. Modern .NET runs well on Windows Server, and moving to Linux or containers can come later.
Which version of .NET to target
Target the current long-term support (LTS) release. At the time of writing that is .NET 10, released in November 2025 and supported until November 2028. .NET 8 reaches the end of its support in November 2026, so a migration starting now should not aim for it.
Release in small steps
Each migrated piece should go to production on its own, with monitoring in place and a simple way to send traffic back to the old code if needed. Small releases keep the risk small and show the business progress month by month.
When a rewrite does make sense
Sometimes the business has changed so much that the old system no longer reflects how it works, or the code is so tangled that migrating it would cost more than starting again. Even then, the same principles apply: replace it one area at a time, keep the old system running until each new part is proven, and test against real behaviour.
In summary
- List what you have before deciding what to do.
- Add tests that capture today's behaviour.
- Move shared libraries first.
- Put modern ASP.NET Core in front and migrate one area at a time.
- Target the current LTS release of .NET.
- Release small, monitor, and keep a way back.
.NET is the stack we specialise in. If you have an older .NET Framework system and want an honest view of your options, book a free consultation and we will look at it with you.