Where money is the system of record.

Calvrix runs Microsoft-stack platforms for enterprises where the work is unforgiving: revenue, settlement, multi-currency, multi-gateway, multi-storefront. .NET Framework 4.8 → .NET 10, Azure-native, with the continuity the business actually depends on.

.NET 10modern target runtime
EF Coretransactional data
Azureapp service · functions · sql · key vault
.NET 4.8maintained until safe to retire
// Runtime

Modern .NET, framework, and live migration between them.

Project model, dependency model, packaging, deployment, runtime upgrades. .NET 10 today; .NET Framework 4.8 maintained until safe to retire.

// Data

Entity Framework Core engineered for correctness.

Migrations, query performance, transactional integrity, schema evolution. Domain models that survive seven-year platform lifetimes.

// Infrastructure

Azure-native, production-grade.

App Service, Functions, SQL, Key Vault, Service Bus. Deployment safety, secret management, observability, cost discipline: built in from day one.

// Workflows

Audit-grade financial systems.

Money, ledgers, settlement, commission. Where the system is the source of truth. Designed for reconciliation, replayability, and provable correctness.

The cost of waiting is not zero. It just shows up late.

.NET Framework 4.8 is in long-term support, not active development. Every year a workload stays on Framework, the surface of the problem grows: dependencies fall out of patch coverage; the ecosystem of compatible libraries thins; the available engineering pool that has Framework muscle memory shrinks; cloud-native runtime cost-per-request widens against modern .NET; and the operational gap between what Framework can be observed to do and what modern .NET surfaces by default keeps growing.

Modern .NET is faster, cheaper to run, and dramatically more observable. Project SDK-style projects are easier to reason about than packages.config-and-csproj sprawl. AOT compilation is genuinely viable for hot paths. Diagnostic tooling (dotnet-counters, dotnet-trace, dotnet-dump) ships in the runtime. Container images are an order of magnitude smaller. The default web stack (Kestrel) outperforms IIS-hosted Framework for the workloads Calvrix typically sees.

None of which means "modernise this weekend." It means the cost of the modernisation engagement compounds the longer it is deferred. The systems that are most expensive to modernise (multi-storefront commerce, multi-gateway payment routing, settlement-grade ledgers) are precisely the ones that benefit most from the move, because their operational reality is harder to fix on Framework than the migration itself would have been.

Calvrix runs these migrations live, with the business continuing to operate. The first contract is two weeks of audit; the migration itself follows the strangler-fig discipline. See the live-modernisation page for the migration method in detail.

What actually changes between .NET Framework 4.8 and .NET 10.

"Migrating to .NET 10" is a phrase that hides a list of concrete decisions. Below is the surface that almost every Calvrix .NET modernisation touches, and the way the choice falls inside Calvrix's operating standard.

01

Project SDK.

packages.config + csproj sprawl → SDK-style csproj. The package graph is explicit, transitive references are visible, and the .csproj diffs become readable in a pull request again. We move this first; everything downstream is easier once the project file tells the truth.

02

Target framework.

.NET Framework 4.8 → net10.0 for libraries with no UI surface, with multi-targeting (net48;net10.0) used during the migration window to let services consume both. Framework support is retired per-assembly, not per-solution, so the migration can advance one assembly at a time.

03

Hosting model.

IIS + System.Web → Kestrel + ASP.NET Core. The hosting boundary moves; controllers and Razor pages port largely intact; OWIN middleware ports to the ASP.NET Core middleware pipeline; HttpModules and HttpHandlers get rewritten to middleware. Out-of-process IIS hosting remains an option during the cutover phase.

04

Configuration.

web.config / app.config → appsettings.json + IConfiguration. Connection strings, AppSettings, custom config sections all migrate. The opportunity is to centralise secrets in Key Vault and remove every plaintext connection string from source control at the same time.

05

Data access.

Entity Framework 6 → Entity Framework Core (or Dapper for the read-heavy hot paths). EF6 → EF Core is not a syntactic rename: query translation, change tracking, and migration tooling all behave differently. We port one bounded context at a time, run dual-stack against shadow traffic, and only retire EF6 once the read/write parity is verified.

06

Logging and telemetry.

log4net / NLog / custom trace listeners → ILogger + OpenTelemetry. The wire format changes; the consumer (Azure Monitor / Application Insights / Datadog / Grafana stack) is chosen per engagement. The point of the upgrade is the dimensional richness OTel brings, not just doing the same thing more verbosely.

07

Background work.

WCF / WebJobs / Windows Services → Azure Functions or hosted services (IHostedService) inside the main process. The migration target depends on workload shape: queue-driven background work tends to land cleanly on Functions; long-running stateful workers stay in-process.

08

Deployment.

Web Deploy / MSI / manual IIS → container images shipped through reviewed CI/CD. The application packaging is the migration's most visible artefact and is the moment the operating standard takes over from the pre-migration habits.

Strangler-fig in practice: what actually happens, day to day.

The strangler-fig pattern is widely cited and rarely operationalised. In a Calvrix engagement it means: at any moment of the migration, the Framework path and the modern .NET path both exist in production, both can serve a given request, and the production decision of which one to use is governed by a feature flag: sometimes a global one, more often a per-customer or per-route one.

Traffic shifts incrementally. We typically begin with 1% of live traffic on the modern path for a defined observation window, long enough to surface low-frequency edge cases that synthetic testing will not catch, then 5%, 20%, 50%, 100%. Each step gates on observability evidence: error rate parity, latency parity (in both directions; a faster path is also a behavioural change worth investigating), response-body parity for the same input where reconciliation is feasible.

Dual-running is not optional. For workloads with reconciliation surface (payments, ledgers, settlement) both paths receive the request, both produce the answer, and a reconciler compares the two before the modern path is allowed to advance. This is the same operating discipline Calvrix applies to gateway routing changes and ledger-path migrations. The cost is engineering time; the alternative is finding the divergence on quarter-end close.

Every transition is reversible until the Framework path is intentionally retired. The retirement itself is a written decision: an ADR documenting that the modern path has met the success criteria, the observability is sufficient, and the rollback option is being relinquished. The Framework binary stays in source control; the runtime is no longer reachable.

What you cannot skip: even when the project is behind.

Every modernisation engagement reaches a point where shortcuts look attractive. Each item below is on the list because Calvrix or our customers have paid for the omission of it in a previous engagement. None of them are skippable.

Observability before traffic. The modern path is instrumented to parity with the Framework path before it receives a single live request. ILogger + OpenTelemetry, with the same dashboards, alerts, and SLO definitions running against both paths.
Reversibility per step. Every change (code, schema, infrastructure) has a documented rollback that has been rehearsed at least once in a non-production environment. An untested rollback is a wish, not a plan.
Dual-running on reconciliation-bearing paths. Payments, ledgers, settlement: both paths process the request, the answers are compared, and the modern path is not promoted until parity is verified for the agreed observation window.
ADR for every irreversible decision. Schema changes that cannot be rolled back, package retirements, hosting cutovers: written down before they ship, with the named approver and the evidence the call was made on.
Tests that cover the migration boundary, not just the units. The most expensive bugs in a .NET modernisation are not unit-level: they are at the boundary where the Framework path and the modern path interact. Integration tests against production-shaped test data are mandatory.
A retirement plan. The Framework path does not stay running forever. The engagement contract names the conditions under which the Framework binary is retired, the audit trail it produces on exit, and the named senior owner who signs off.

The migration patterns that fail, and why.

The five patterns below are the ones that recur in long-lived .NET estates. They share a common structure: a decision that looked rational on a slide and that the production system disagreed with.

01

The rewrite.

The team decides the .NET Framework codebase is so encrusted that a fresh build is faster than a migration. Eighteen months later, the rewrite has matched 40% of the original feature set, the Framework codebase is still in production, and the engineering team has accumulated debt in both. Rewrites fail because the original codebase encodes years of edge-case knowledge that nobody has written down. The strangler-fig discipline preserves that knowledge by migrating around it.

02

The big-bang cutover.

A go-live weekend. The team plans for every contingency they can think of. The production system finds one they did not. The rollback path either does not exist or has not been rehearsed. We do not do go-live weekends. Traffic ramps; rollbacks are warm; the migration completes in a series of unremarkable Tuesdays.

03

Ignoring the integration layer.

The team scopes the migration as the application code. The integration layer (message contracts, partner APIs, ETL feeds, scheduled jobs) is invisible until cutover. We do not quote a migration that does not include an integration audit in week one. The integration layer is usually 30–50% of the real work.

04

Deferring the test suite.

"We'll add integration tests as we go." The team ships the migration first; the tests never quite get prioritised; six months in, the team is afraid to make changes because there is no safety net. The migration is the moment to land the test suite that should have existed already. We build the boundary-test layer before the strangler-fig starts.

05

Mocking out the database.

Integration tests against an in-memory database. Production hits SQL Server. The tests pass; production breaks on transaction isolation, deadlocks, or the truncation behaviour of a column that the mock does not enforce. Mocking the data layer is a way of guaranteeing the test suite cannot find the bugs that production will.

Where the modernised platform actually lives.

The runtime upgrade is half the work; the other half is landing the modernised application on Azure-native infrastructure that the operating standard can hold. The components below are what almost every Calvrix .NET modernisation engagement converges on.

App Service / Container Appsweb tier · scale to demand · slot-based deployment · health probes
Azure Functionsevent-driven background work · queue triggers · scheduled jobs
Azure SQL · Hyperscaletransactional store · point-in-time restore · read replicas · 100TB headroom
Key Vault + Managed Identitysecret storage · keyless authentication · audit trail by default
Service Bus + Event Gridreliable messaging · publish/subscribe · dead-lettering · ordering guarantees
Application Insights + Monitordistributed tracing · live metrics · alert rules · log analytics
Front Door + Private Endpointsedge entry · WAF · TLS termination · private network connectivity
Bicep / Terraforminfrastructure-as-code · per-environment parity · reviewed change

The shape adapts to the customer's existing Azure investment and compliance posture. The constants are: secrets out of source control, identity out of connection strings, observability dense enough to operate the platform from, and infrastructure declared in code that survives the people who wrote it.

What we will not quote, and why.

Selectivity is part of the standard. The engagements below are ones Calvrix declines on principle, accepting them would compromise the operating standard the engagements we do take depend on.

Rewrites disguised as migrations. If the engagement asks for a green-field .NET 10 build that runs in parallel with the Framework system "until cutover," that is a rewrite. We will tell you why it will not work and decline the brief.
Migrations that require a production freeze. If the business cannot tolerate a live migration, the brief is not a migration: it is a stop-the-world rebuild, and Calvrix does not run those.
Quotes that ignore the integration layer. A scope that names only the application code is incomplete. We will widen the audit to include the integration surface or decline.
Fixed-price migrations against unverified codebases. We will quote the audit fixed-price. The migration itself is a senior retainer plus milestone payments against a plan the audit produced.
Engagements without a named senior owner on the customer side. Modernisations require co-ownership. If there is no named technical owner on the customer side who can approve ADRs, the engagement will not succeed and we will decline.

What buyers ask about .NET modernisation.

Every modernisation we have been pitched turns into a rebuild. What does yours actually involve?

A live migration from .NET Framework 4.8 (or older) to modern .NET (currently .NET 10), executed as a sequence of small, reversible, observable transitions. We do not rebuild the platform; we modernise it in place. The application stays online for the entire migration.

We need a date for the board. How long does a .NET Framework to .NET 10 migration take?

It depends on the surface area, the test coverage you start with, and how much of the integration layer is third-party. A focused single-service migration is weeks. A multi-storefront, multi-gateway commerce platform is measured in quarters. We will not give a quote that ignores the integration surface.

We were burned by a rewrite once already. Will you rewrite our codebase?

No. Rewrites fail. We modernise in place using the strangler-fig pattern: new and old paths run side by side, traffic is shifted incrementally with feature flags, and any single step is reversible. The business does not stop because the engineering is in flight.

We want to move to Azure at the same time. Can that run alongside the .NET upgrade?

Yes. The two are normally co-ordinated: as services come off .NET Framework, they land on Azure App Service / Functions / SQL / Key Vault with the operating posture we hold them to: managed identity, observability, secret rotation, infrastructure-as-code.

Have you actually done this at our scale, or only in theory?

A multi-storefront commerce platform in continuous production since 2019, currently mid-flight on a .NET Framework 4.8 → .NET 10 migration. The platform belongs to the customer, so its trading figures are theirs to publish, not ours.

We have standardised on .NET 8 for compliance and cannot jump to 10. Does that rule us out?

No. .NET 10 is our target runtime because it is the current long-term-support release, but engagements that land on .NET 8 are common when a customer has hardened on a specific LTS for their compliance posture.