Skip to content
SERVICE

ASP.NET Web Forms to ASP.NET Core Migration

ASP.NET Web Forms has no equivalent in ASP.NET Core, so pages have to be rebuilt rather than ported. We move them a slice at a time, with the Web Forms application still serving everything it has not handed over yet and a reverse proxy in front so users see one site.

WHAT THIS INVOLVES

The scope, and what has to get right.

  • STRANGLE Strangler Fig, not a rewrite. New ASP.NET Core 8 code takes over features one at a time while the Web Forms application keeps running. Nothing is switched off until its replacement handles the work.
  • YARP A reverse proxy in front. YARP routes each request to either the old or the new application. Users see one site at one address, and moving a feature is a routing change.
  • SLICES Vertical slices. Each feature moves end to end, taking its UI, its logic and its data access together, rather than migrating a whole layer at a time.
  • TRACKS Two parallel tracks. The web application is one track. Console applications and scheduled jobs are the other, and they need their own plan rather than being assumed to follow.
  • SHADOW Shadow mode for outputs. Where documents go to a trading partner, the new code produces them alongside the old and the outputs are compared before anything is switched over.
WHY IT IS NOT A PORT

Web Forms has no direct path to ASP.NET Core

ASP.NET Core does not include Web Forms. There is no compatibility shim, no project upgrade that keeps .aspx pages working, and no supported way to run the Web Forms page lifecycle on the new platform. The postback model, view state and the server control hierarchy simply do not exist there.

That means pages are rebuilt as MVC or Razor Pages rather than converted. It sounds worse than it is: the rebuild is mostly mechanical for simple screens, and the real work is extracting the business rules that sit in code-behind files so they can live somewhere testable.

This is the same extend-rather-replace discipline described on legacy ASP.NET modernization, applied to a platform gap rather than to a language change.

THE APPROACH

Strangler Fig with a reverse proxy

The Strangler Fig pattern grows the new application around the old one. New ASP.NET Core 8 code takes over one feature at a time, and the Web Forms application keeps serving everything that has not moved yet. There is no date when everything changes at once.

A YARP reverse proxy sits in front of both and routes each request to whichever application owns that path. To a user there is one site at one address, and they cannot tell which half answered. Handing a feature over becomes a routing decision you can reverse in a moment if something is wrong.

This is how we completed a Web Forms to ASP.NET Core 8 migration for a US consumer electronics brand, with the next phase now underway. That system has to keep taking orders throughout.

SLICES

Move vertical slices, not layers

The tempting plan is to migrate by layer: all the data access, then all the logic, then the screens. It fails because nothing works until the last layer lands, so there is no point at which you can prove progress or stop safely.

A vertical slice takes one feature end to end, its screen, its rules and its queries, and moves the whole thing. When the slice is done it is genuinely done: it serves real users and can be verified against the old version of the same feature.

Slice order is a risk decision rather than an importance decision. Something with heavy traffic and simple rules exercises the proxy, the authentication and the deployment path properly while a mistake stays cheap.

EASY TO FORGET

The jobs and console applications are a second track

Most Web Forms systems of any age have work running outside the web application: console applications on a schedule, batch processes, overnight imports and exports. They do not appear anywhere in the web project, which is why they are usually missing from the plan.

They need their own migration track, running in parallel with the web application rather than after it. They often share data access code with the web tier, so the order in which the two tracks move has to be agreed rather than discovered.

VERIFYING

Shadow mode before the switch

For anything that produces output another party depends on, such as documents going to a trading partner, the new code runs in shadow mode first. It generates the same documents alongside the old code, and the two outputs are compared.

Only once the new output matches does it take over as the real one. That turns a nervous cutover into a comparison you can run as many times as you like, and it catches the differences that only appear on real data rather than on test cases.

The same comparison discipline, applied to Classic ASP rather than Web Forms, is set out step by step in our Classic ASP to ASP.NET migration guide.

DEPENDENCIES

.NET Framework libraries, and what to check first

Before any slice moves, the dependencies decide what is possible. Check which packages have a version that runs on current .NET, which Windows-only components the application relies on, and which third-party libraries are still maintained at all.

Anything with no forward path is a decision rather than a blocker: wrap it and keep calling it for now, replace it, or let it hold a slice back while the rest proceeds. What matters is knowing which before planning the order, not discovering it halfway through a slice.

Where a dependency cannot move yet, that is an argument for landing on ASP.NET MVC on .NET Framework first rather than going straight to Core. Our .NET development work covers both targets.

HOW WE BUILD IT

Inside the system, not bolted on.

01

The old application stays the reference

Until a slice is switched over, the Web Forms version is what the new one is measured against, because it is the only complete statement of the rules.

02

One slice in flight at a time

Several slices at once makes it unclear which change caused a problem. Finishing one before starting the next keeps every regression traceable.

03

Rollback is a routing change

Because the proxy decides which application serves a path, reverting a slice does not need a deployment. That is what makes moving a feature a low-risk step.

QUESTIONS

Common questions.

What does the Strangler Fig pattern actually mean here?

The new application grows around the old one feature by feature, taking over its work gradually, until the old one has nothing left to serve. The name describes the shape of the migration, not a tool you install.

What is YARP doing in this setup?

It is a reverse proxy that decides, per request, whether the old or the new application answers. It is what lets both halves live behind one address, so handing a feature over is a routing change rather than a release.

Do our scheduled jobs and console applications have to move as well?

Yes, and they are planned as their own track running alongside the web work. They are the part most often left out of an estimate, because nothing in the web project refers to them.

How do you prove the new code produces the same output?

For anything another party receives, the new code runs in shadow mode and generates the output alongside the old code so the two can be compared on real data. The switch happens only once they match.

What if a library we depend on has no version for current .NET?

It is checked before planning rather than discovered mid-slice. Depending on what it does, it gets wrapped and kept for now, replaced, or allowed to hold one slice back while the rest of the migration continues.

LET'S TALK

Running a Web Forms application that cannot go offline for a rewrite?

Tell us what it depends on and what runs outside the web application, and we will tell you which slice is the sensible one to move first.

Start a project