When to Modernize Your Legacy .NET Application (And When Not To)
When to Modernize Your Legacy .NET Application (And When Not To)
Your .NET Framework 4.6 application works. It processes orders, generates reports, handles the business logic that keeps the company running. Nobody touches it unless something breaks. Deployments happen once a quarter — if you are lucky — and they involve a nervous developer, a checklist from 2018, and a prayer.
Sound familiar? You are sitting on a legacy .NET application, and someone in leadership is asking whether it is time to modernize. The answer is not always yes. But when it is yes, doing it right saves you years of pain. Doing it wrong costs you the same.
I have modernized .NET applications for Nordic SMBs for the past decade — from small internal tools to full line-of-business platforms with 50+ developers. Here is how I think about when to pull the trigger and when to leave things alone.
Five Signs Your .NET App Needs Modernization
Not every old application is a problem. Some .NET Framework apps will run fine for another decade. But these symptoms mean the clock is ticking.
1. Releases take weeks, not hours. If deploying a bug fix requires a full regression cycle, manual IIS configuration, and a maintenance window at 02:00 on a Saturday, your delivery pipeline is the bottleneck. Modern .NET with containerized deployments and CI/CD can get that down to minutes.
2. You cannot hire developers who want to work on it. Try posting a job ad for a .NET Framework 4.5 developer in Copenhagen or Stockholm in 2026. The candidates who respond will either be expensive specialists or junior developers who will struggle with the ancient toolchain. New graduates learn .NET 10, not Web Forms.
3. Security patches are getting harder — or impossible. .NET Framework 4.8 is in maintenance mode. Microsoft is not adding new features or backporting security improvements from .NET 10+. If your application depends on libraries that have stopped supporting .NET Framework, you are accumulating risk every month.
4. Your hosting costs are climbing for no reason. Legacy .NET Framework apps typically run on Windows Server with IIS. Windows Server licensing, especially in on-prem or hybrid setups, is significantly more expensive than running .NET 10 on Linux. One client I worked with cut their hosting costs by 40% just by moving from Windows VMs to Linux containers — before optimizing anything else.
5. Integration with modern tools is painful. Need to add OpenTelemetry for observability? A modern authentication provider like Keycloak? A message queue for async processing? In .NET Framework, each of these is a fight. In .NET 10, they are NuGet packages and a few lines of configuration.
If you are nodding at three or more of these, modernization is worth scoping. If you are only seeing one, you might be fine for now — read the "when not to modernize" section before making any decisions.
The .NET Application Modernization Spectrum
Modernization is not a binary choice. There is a spectrum, and where you land depends on your budget, timeline, and how far gone your current architecture is.
Rehost (Lift and Shift)
Move the application to new infrastructure without changing the code. Put it in a container or a new VM, update the deployment scripts, done.
Best for: Applications that work fine but are stuck on expensive or end-of-life infrastructure. A .NET Framework app running on a Windows Server 2012 VM is a candidate.
Cost: Low. Days to weeks.
What you get: Lower hosting costs, better infrastructure automation. The application itself is unchanged.
What you do not get: Any of the developer experience or performance benefits of modern .NET.
Re-Platform
Upgrade the runtime and framework version while keeping the overall architecture. Migrate from .NET Framework 4.x to .NET 10, replace deprecated libraries, update the build pipeline.
Best for: Applications with decent architecture that are held back by the framework version. If the code is reasonably structured — controllers, services, repositories — re-platforming is often the sweet spot.
Cost: Medium. Weeks to a few months, depending on size.
What you get: Modern runtime performance (often 2–5x faster for API workloads), Linux hosting, current library ecosystem, easier hiring.
What you do not get: A fix for fundamental architecture problems. If the codebase is a tangled mess of static classes and God objects, re-platforming puts a new engine in a car with no steering wheel.
Re-Architect
Restructure the application while migrating. Break a monolith into bounded contexts or services. Introduce proper domain modeling. Fix the sins of the past.
Best for: Applications where the business logic is valuable but the architecture prevents the team from moving fast. Typically systems that have grown organically for 8+ years.
Cost: High. Months. Requires experienced architects.
What you get: A maintainable, testable system that the team can extend without fear. Plus all the re-platform benefits.
What you do not get: Speed. This is the slowest option, and the risk of scope creep is real.
Rewrite
Start from scratch. New codebase, new architecture, modern stack from day one.
Best for: Almost nothing. I am serious. Rewrites are the most expensive, highest-risk option and should be a last resort. The only time I recommend a rewrite is when the existing code is so unmaintainable that understanding it takes longer than rebuilding it — and that is rarer than most people think.
Cost: Very high. 6–18 months. Budget overruns are the norm, not the exception.
What you get: A clean codebase — if you get it right.
What you do not get: Guarantees. Joel Spolsky wrote about this in 2000 and the advice still holds: rewrites kill companies. The old system encodes years of business rules, edge cases, and institutional knowledge that no specification document captures.
.NET Framework to .NET 10: What Actually Changes
If you are going the re-platform route — and for most Nordic SMBs, this is where I start — here is what the migration involves in practice.
The Big Shifts
Project and solution file format. Old-style .csproj files with hundreds of lines of XML become the new SDK-style format. Solutions get the same treatment — the new .slnx format replaces the legacy .sln with a clean, readable XML file that is easy to diff and merge. This alone makes the project manageable.
<!-- Before: .NET Framework csproj (abbreviated — the real ones are 200+ lines) -->
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\...\Microsoft.CSharp.targets" />
<PropertyGroup>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<!-- ... 40 more properties ... -->
</PropertyGroup>
<!-- ... ItemGroups with explicit file references ... -->
</Project>
<!-- After: .NET 10 csproj -->
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
</Project>Dependency injection is built in. If your .NET Framework app uses Autofac, Ninject, or Unity, the built-in DI container in .NET 10 handles most scenarios. One less dependency to maintain.
Configuration moves from web.config to appsettings.json. The new configuration system supports environment-specific overrides, user secrets, and environment variables out of the box. No more XML transforms.
Entity Framework → EF Core. The migration path is well-documented but not trivial. Lazy loading works differently, some LINQ queries need rewriting, and the migration tooling has changed. Budget a week for a medium-sized data layer.
Authentication and Identity. If you are using ASP.NET Identity or Windows Authentication, the migration requires attention. ASP.NET Core Identity is a different library with a different API. If you are planning to introduce Keycloak or another OpenID Connect provider, modernization is a good time to make that switch.
What Catches Teams Off Guard
System.Web is gone. Completely. If your code references HttpContext.Current, System.Web.Mvc, or any System.Web namespace, every one of those calls needs to be replaced. For large codebases, this is the single biggest migration task.
SOAP/WCF services. .NET 10 has limited WCF client support via CoreWCF, but if you are hosting WCF services, you need to rewrite them as REST or gRPC endpoints. There is no direct migration path.
Global.asax and HTTP Modules. The request pipeline is completely different. Startup.cs (or the new minimal hosting model) replaces Global.asax. HTTP modules become middleware. The concepts map cleanly, but the code does not copy-paste.
Third-party library compatibility. Check every NuGet package you depend on. Many have .NET 10 versions, but some are abandoned or have been replaced by alternatives. The .NET Upgrade Assistant tool flags these, and it is worth running early.
The Tool That Helps
Microsoft's .NET Upgrade Assistant automates the mechanical parts: project file conversion, namespace changes, known API replacements. It will not fix your architecture, but it handles the tedious work. Run it first, then fix what it cannot handle.
# Install and run the Upgrade Assistant
dotnet tool install -g upgrade-assistant
upgrade-assistant upgrade ./YourSolution.slnIn a recent re-platform project, the Upgrade Assistant handled about 60% of the changes automatically. The remaining 40% was manual work — mostly replacing System.Web references and updating EF queries.
When NOT to Modernize
Here is the part most consultants skip: sometimes the right answer is to leave your legacy .NET application alone.
The application is stable and requirements are frozen. If the system processes invoices the same way it has for five years, nobody is asking for new features, and it runs without issues — why touch it? Modernization has real risk. If the risk is not justified by a real need, the smart move is to leave it running.
The business case does not add up. Modernization costs money. If the application will be decommissioned in two years because the business is switching to a SaaS product, spending six months re-platforming it is a waste. Ask the hard question: how long will this application need to exist?
You do not have the team for it. A .NET Framework-to-.NET 10 migration requires developers who understand both. If your team only knows .NET Framework and you cannot bring in experienced help, the migration will take 3x longer and introduce bugs you did not have before.
The application is a small internal tool. A small WinForms app used by five people in accounting does not need to be on .NET 10. If it works and the maintenance cost is near zero, let it be.
You are doing it for the resume. This sounds absurd, but I have seen it. A team pushes for modernization because they want to work with the new tech, not because the business needs it. Modernization should be driven by business outcomes — reduced costs, faster delivery, lower risk — not by developer boredom.
How to Scope and Budget a .NET Modernization Project
If you have decided to move forward, here is how I scope these projects for Nordic SMBs.
Step 1: Audit the Codebase
Before estimating anything, you need to understand what you are working with.
- Lines of code (rough indicator of size)
- Number of projects in the solution
- .NET Framework version(s) in use
- Third-party dependencies and their .NET 10 compatibility
- Database access layer (raw ADO.NET, EF6, Dapper, stored procedures)
- External integrations (SOAP services, file shares, third-party APIs)
Run the .NET Upgrade Assistant in analysis mode to get a compatibility report.
Step 2: Pick Your Strategy
Based on the audit, choose your point on the spectrum. Most Nordic SMBs I work with land on re-platform for the core application, with selective re-architecting of the worst modules.
Step 3: Estimate in Phases
Break the work into phases that deliver value independently. Do not plan a six-month migration with value only at the end — that is how projects get cancelled.
Phase 1 — Core API migration. Get the backend running on .NET 10 with existing functionality. 4–8 weeks for a medium-sized application.
Phase 2 — Infrastructure modernization. Containerize, set up CI/CD, deploy to Linux. 2–4 weeks, can overlap with Phase 1.
Phase 3 — Data layer migration. EF6 to EF Core, database schema cleanup. 2–6 weeks depending on complexity.
Phase 4 — Frontend and integration cleanup. Update any tightly coupled frontend code, replace deprecated integrations. 2–4 weeks.
Ballpark Budget
For a typical Nordic SMB application (50–200k lines of code, 10–30 projects in the solution, one database):
- Re-platform only: DKK 300,000–600,000 (€40,000–€80,000)
- Re-platform with selective re-architecture: DKK 500,000–1,200,000 (€67,000–€160,000)
- Full rewrite: DKK 1,500,000+ (€200,000+) — and it will go over budget
These numbers assume a senior .NET developer or a small team working focused hours. Your actual cost depends on codebase size, architectural debt, and how many System.Web references your search turns up.
Next Steps
If your .NET Framework application is showing the symptoms I described above, start with the audit. Install the .NET Upgrade Assistant, run the analysis, and get a clear picture of what a migration would involve. That costs you an afternoon, not a budget approval.
If you want an experienced set of eyes on the analysis — someone who has done this migration multiple times for Nordic companies — book a free 30-minute assessment call. I will tell you honestly whether modernization makes sense for your situation, and what it would realistically cost.