Modernization case study · anonymised

About 600,000 lines moved from .NET Framework 4.8 to .NET 10 and onto Linux

A Nordic business software company moved six web applications and their shared core libraries from a Windows-only .NET Framework to .NET 10 on Windows and Linux, changing business logic only where the migration required it.

.NET Framework 4.8 · Windows.NET 10 · Windows and Linux

Key takeaways

  • A .NET Framework 4.8 system tied to Windows-only libraries, with no complete test material – and running on Linux as a firm requirement.
  • The current behaviour was recorded first, and the move was done in reviewed steps, with the customer approving the plan for each one.
  • On the final code, the 9,149-test suite runs without failures on Windows and Linux. The work was handed over in November, with 30 differences listed for the customer to sign; the customer's final acceptance testing comes next.
Industry
Business software (SaaS)
Company
Software company, Nordics, under 50 people
System
Six web applications on two shared core libraries – about 600,000 lines at the start
Stack
.NET Framework 4.8 (Windows only) → .NET 10 on Windows and Linux
Status
Handed over in November 2026; final acceptance testing to follow

0 failures in the 9,149-test suite on Windows and Linux · 39 of 39 API requests equal to the old system's answers · 30 differences listed for the customer's signature

Why now

The company's main application family ran on .NET Framework 4.8 and only on Windows: its map drawing and geometry relied on libraries that run only on Windows. The company wanted a modern .NET and, as a firm requirement, the ability to run on Linux, where servers cost less – and, along the way, to clear out duplicate and dead code and bring the structure in line with its own code standard, without changing the business logic. There was no complete test material: many features, hundreds of data models and integrations, and much of the logic in configuration.

What we did

Map – June 2026. The customer was onboarded to the Agentic Engineering OS, and its Knowledge Core was generated from the code. For the migration itself, our engineer worked from an implementation plan and a deep dive into the core libraries, with the customer answering the scope questions.

Define – June–July 2026. Before changing anything, we recorded what the running system did, working in Claude Code with a method file in the customer's repository. The customer reviewed and approved each slice of the first phase in two steps – first the direction (scope, approach, how it would be proven), then clearance to write code. Code was removed only after checks showed production no longer used it; a few removals later proved wrong and were restored.

Rebuild – June–November 2026. The work was done by one engineer at about a fifth of full time, with AI agents in Claude Code, in two phases. Phase 1 (June–July): all six web applications and the core libraries were ported to .NET 10 on Windows and Linux, and data access moved to Entity Framework Core. Phase 2 (September–October): the core libraries were split into layered libraries, Entity Framework Core was upgraded to version 10, duplicate and dead code was removed, and the design was refactored towards the customer's code standard. The customer's review found the structure did not yet follow that standard closely enough; the standard was refined and the structure reworked to it – 31 projects in three layers – before the phase closed at the start of November.

Accept – from August 2026. From August the customer deployed each phase to its own test environments through its own build pipeline and ran several rounds of testing; its testers and support team reported findings, which were fixed – most by us, some by the customer's own developers – and re-verified. The hand-over at the start of November gave the customer a staging checklist, a list of differences to sign and the open decisions. The customer's final acceptance testing is the next step.

What it took from the customer. The customer's CTO set the scope and made the key technical decisions. Most of the testing on the customer's side was done by one person, at about a third of his time, with the support team joining in during testing. One person answered the first phase's questions and reviewed its slices; another provided test data, test environments and bug reports, defined the target code structure and reviewed the later work. The customer gave access to the code, most of its development databases and its development environment; the build pipeline stayed in its hands, and production was never touched.

Proof

The tests ran on recordings of the running old system, a local test database and the customer's development environment. No production business data was used – the only production inputs were configuration – and sign-in was tested against the real identity service of the development environment.

On the final code, the 9,149-test suite runs without failures on Windows, on Linux and on Linux with the server clock in UTC, and 39 of 39 API requests match the old system's answers on the same day. The checks went beyond unit tests: recordings of the old system's behaviour, API answers compared with the old system's, runs on three platform set-ups, and 77 architecture rules enforced by the build.

Scope and limits

Out of scope: a native mobile wrapper, database schema changes and the database-driven configuration. Business logic changed only where the migration required it.

Not everything went to plan. Before anything was deployed, live sign-in testing found 19 regressions, all fixed. Once the customer deployed the new code to its own development environment on Linux, its testers and support team found more: calls that only worked on Windows, time-zone handling that broke when the server ran in UTC, a page whose fix had been made in a file the application no longer served, one of our time-zone fixes that broke other callers, and a write from the new application that broke the old one for the same user, because both share one database. Our own audit of the second phase found 16 defects behind green test suites, on a build already deployed for testing. Each was fixed and covered by a test, and the Windows-only and time-zone classes now have automatic checks in the build. The customer's review of the second phase found that the new structure did not follow its code standard closely enough; reworking it became the last part of that phase. Still open at hand-over: 30 differences for the customer to sign, nine open decisions and a staging checklist – and the partner integrations have not yet been exercised, as no test called a partner system.

What stays with the customer

The test suites and recordings built during the work, with 77 architecture rules enforced by the build; the approved slice specifications; a codebase on .NET 10, in three layers, running on Windows and Linux; a team trained in the AI-assisted workflow; and a hand-over with a staging checklist, the differences to sign and the open decisions.

What it means for you

This engagement was larger than a First Slice – a whole application family over five months – but the method is the same: map the system from its code, pin down what it does today, rebuild in bounded steps with your people reviewing each one, and prove the result against the old system. After the first slice, the next slices follow a sized plan, the same parity checks carry on, and the Agentic Engineering OS keeps the system map, requirements and evidence for your own team. Your first slice starts with a 60-minute scoping call.

Published without the customer's name. Figures are from the engagement record.

Book a scoping call

Tell us about your system

Pasi Vuorio

Pasi Vuorio

CEO

Gaurav Khullar

Gaurav Khullar

CPO

Pick a time that suits you

In a 60-minute scoping call we look at your system together, name a candidate first slice, and agree the next step. Give us read access after the call, and we size the candidate slices before you commit.

Day

Time (Helsinki)

Checking the calendar…

See the First Slice offer