A legacy system can be hard to deploy, secure or change and still be what keeps invoices moving and month-end reports coming out. Its code may also hold business rules that are not written down anywhere else.
Where a rule is not recorded in documentation, contracts or anyone's working notes, the old code is the only specification of it, even when that code is painful to read. A plan that deletes the system before using it as a reference can end up rediscovering such rules from user complaints after cutover.
What the current system quietly enforces
Before choosing a framework or drawing the new architecture, find out what the current application actually protects. An Access database may generate the only report finance trusts. A desktop app may hold the pricing override sales uses at quarter end. A SQL Server stored procedure may be the only place that knows which customers get special billing treatment, or a nightly import may skip rows with a missing account code for a reason nobody remembers.
Trace each workflow to the data it reads and writes: which screens, reports, scheduled jobs, integrations and user roles touch it, and where it fails today. Rules that live in stored procedures and scheduled jobs can be missed because no screen shows them.
Replacing it in phases, and where rollback gets expensive
A full rebuild is sometimes the right call, for example when the platform can no longer be patched or the source code is gone. Otherwise a phased replacement gives the business more chances to find hidden rules while the old system still runs. Stabilizing the current system comes first: source control, backups, repeatable deployments and logging make later steps easier to reverse.
Microsoft's Strangler Fig pattern describes the phased route. A facade intercepts requests and sends each one either to the legacy application or to the new service that has replaced that piece. The same page lists when the pattern does not fit, including when requests to the old back end cannot be intercepted and when the team cannot modify the legacy source to switch off migrated features. For a Microsoft-stack system the new pieces can be current .NET, ASP.NET Core and SQL Server, which is where .NET development and modernization meet.
The detail worth planning around is in Microsoft's database example. While one domain is being moved, change data capture keeps the new domain database in sync with the monolithic one, and the business can still roll back to the old tables. Once the legacy tables, stored procedures and sync processes for that domain are removed, rolling back means restoring those objects and replaying every data change made since. Deleting legacy objects is a separate, late decision for each domain, taken only after the new side has passed reconciliation.
When the new report disagrees with the old one
Run the old and new systems side by side on the same period and compare what they produce, starting with the reports people act on, such as the aging report and invoice totals.
A mismatch has more than one explanation. The new code may be wrong. The old code may be wrong in a way users have been correcting by hand, or it may apply a rule nobody documented. Matching the old output exactly can reproduce a known error, and changing it without telling anyone looks like a bug to the people who relied on it.
Record a decision for each difference: keep the old behavior or correct it. For finance numbers, the person who signs off on the finance report makes that call. During the transition, support needs to see which system produced a given record and which version of the rule applied, so a question about a changed total can be answered without reading both code bases.
Related Reading
For the November 10, 2026 end of support for .NET 8 and .NET 9, read What .NET 8 and .NET 9 End of Support Means for Your Business.