Skip to content

Engineering2026-05-14

Moving off .NET Framework without a rewrite

Almost every .NET Framework application we are asked to replace should be migrated instead. Here is the order the work goes in, and the four things that actually block it.

Author
Daniel Okonkwo
Published
14 MAY 2026
Read
6 MIN
Ref
D57A0D

The application works. It has worked for eleven years. It cannot be upgraded, the people who wrote it have gone, and somebody has just quoted you a rewrite.

Before you accept that quote: most of these applications do not need one. The runtime is the problem, not the code, and the runtime can usually be changed incrementally while the application stays in production. I have taken four estates across this way and the pattern holds well enough to write down.

Do this first: find out what actually blocks you

Not what might block you. Run the upgrade assistant, then read the dependency graph yourself, because the tooling reports the symptom and you need the cause.

In practice the blockers fall into four groups, and they are very unequal in difficulty.

Packages with no modern equivalent. Usually the easiest. Most have a successor; a few need replacing with something differently shaped. Budget a day each and expect two to take a week.

System.Web. The genuinely structural one. If the code reaches for HttpContext.Current from a business-logic class — and it will — those call sites have to be untangled before anything moves. This is the bulk of the work in most migrations, and it is also work worth doing regardless of the runtime, because it is what makes the logic testable.

WCF services. Server side needs replacing. Client side is usually fine with the compatibility packages. Do not discover which one you have in month three.

Anything talking to Windows directly. Registry, COM interop, WMI, Windows-only cryptography. Sometimes fine, sometimes the reason a component stays where it is. Find these in week one.

In rough order of how much trouble each causes:

BlockerFrequencyTypical costNotes
Packages with no modern equivalentEvery projectA day eachTwo of them will take a week
System.Web reached from business logicEvery projectWeeksThe bulk of the work, and worth doing regardless
WCF services, server sideCommon1–3 weeksClient side is usually fine on the compatibility packages
Windows-only interopOccasionalDays to neverSometimes the reason a component stays put

The order that works

1. Retarget the class libraries first. Move the shared libraries to netstandard2.0, which both runtimes load. Now the same library builds into the old application and the new one, and you have a bridge instead of a cliff.

2. Untangle System.Web from the logic. Where a business class reads HttpContext.Current, pass the value in instead. This is dull, mechanical and the single highest-value step in the whole exercise. It is also the step people skip, and skipping it is what turns a migration into a rewrite.

3. Stand up the new host alongside the old one. An ASP.NET Core application that serves nothing yet, deployed, in the pipeline, with health checks. It exists so the next step is a routing change rather than a launch.

4. Move endpoints behind a proxy. A reverse proxy in front of both — YARP does this well — routing per path. Move one endpoint. Watch it. Move the next. Both applications are in production simultaneously and traffic can go back within a minute.

5. Delete the old host last. Not in parallel with step four. When the last route has moved and stayed moved for a full reporting cycle.

What this costs

For a mid-sized application — a few hundred thousand lines, a normal dependency set — eight to sixteen weeks with two engineers is the range I would quote. Portside's quoting engine took eleven.

A rewrite of the same application is a year and change, and it is a year during which the business cannot have anything else. That difference is the entire argument.

When a rewrite is right

I am not claiming it never is. Rewrite when:

  • The data model is the actual problem. A runtime change will not fix a schema that was wrong in 2013 and has been worked around ever since.
  • The application is small enough that a rewrite is under three months. Below that threshold the incremental machinery costs more than it saves.
  • The business rules are genuinely obsolete. If half of what the system does should no longer be done, migrating it forward preserves the wrong thing carefully.

Notice that none of those are "the code is old" or "the framework is out of support". Both are true of most of these applications and neither is sufficient on its own.

The thing nobody puts in the estimate

Write down each blocker as you clear it, and how. You will hit the same four categories on the next application, and the second migration should be meaningfully cheaper than the first.

Ours are, and the record of why is the reason.

Daniel Okonkwo, Head of .NET Practice

Written by

Daniel Okonkwo

Head of .NET Practice

Twelve years in C# and counting, six of them on estates somebody else had abandoned. He has taken four applications from .NET Framework onto a supported runtime without a rewrite, including the Portside quoting engine, and he keeps a written record of every migration blocker he has hit so the next one costs less.

Share

Related notes

All notes
  • 01Engineering

    The integration that works until it is retried

    Idempotency is not an advanced topic. It is the difference between an integration that can be operated and one that quietly creates duplicate records for eighteen months.

    Integration · APIs5 MIN
  • 02Delivery

    Measure the process before you automate it

    The most expensive automation failures we are called in to fix all share one property: nobody recorded what the manual process actually cost, so nobody can tell whether the replacement is better.

    Automation · Measurement5 MIN
  • 03AI

    What an AI pilot should cost you before it earns anything

    Most AI pilots stall at the second budget review, and it is almost never because the model underperformed. It is because nobody built the thing that would have proved it did not.

    Generative AI · Evaluation6 MIN