# .NET Framework to .NET 8 Migration: The Strangler Pattern That Actually Works

Microsoft ended active development on .NET Framework at version 4.8.1. There will be no 4.9. There will be no new language features, no performance improvements, no new APIs, and no updates to the ...

## .NET Framework to .NET 8 Migration: The Strangler Pattern That Actually Works

Your .NET Framework 4.x monolith still works — but it is Windows-only, IIS-bound, locked out of C# 12, and maintained by a shrinking developer pool. FreedomDev migrates legacy .NET Framework applications to .NET 8 using the strangler fig pattern: module-by-module extraction behind YARP reverse proxy, zero downtime, zero feature freeze. WCF to gRPC, EF6 to EF Core, ASP.NET MVC to Razor Pages or Blazor — we handle the breaking changes that the .NET Upgrade Assistant flags but cannot fix. Zeeland, MI. 20+ years of .NET migrations across manufacturing, healthcare, financial services, and logistics.

---

## Our Process

1. **Migration Assessment and Compatibility Report (1-2 Weeks)** — We run the .NET Upgrade Assistant and ApiPort analyzer against your entire solution to generate a machine-readable compatibility report: which APIs have direct .NET 8 equivalents, which APIs have behavioral changes, and which APIs have no equivalent and require architectural decisions. We audit every NuGet package for .NET 8 compatibility. We map the dependency graph between projects in your solution to identify which modules can be extracted independently and which are tightly coupled. We document every WCF service contract, every Entity Framework 6 model, every Windows-specific API call, every System.Web dependency, and every COM interop reference. The deliverable is a migration plan with a prioritized module sequence, estimated effort per module, identified blockers that require architectural decisions, and a YARP routing strategy for the strangler fig transition.
2. **Infrastructure and Project Scaffolding (1 Week)** — We set up the parallel infrastructure that enables side-by-side execution. This includes: converting the solution to SDK-style project files, setting up a new .NET 8 solution structure alongside the existing .NET Framework projects, deploying the YARP reverse proxy with initial routing that sends all traffic to the legacy application, configuring the CI/CD pipeline to build and deploy both the legacy and modern applications, setting up shared authentication so that user sessions work across both backends, and configuring the database connection so both EF6 (legacy) and EF Core (modern) can operate against the same database concurrently. At this stage, the YARP proxy is live in production but routing 100% of traffic to the legacy backend — the infrastructure is proven before any migration code ships.
3. **Shared Libraries and Data Access Migration (2-4 Weeks)** — The foundation layers migrate first because every other module depends on them. We convert shared class libraries to multi-target projects (.NET Framework 4.8 and .NET 8) using conditional compilation where the APIs diverge. The data access layer is rebuilt on Entity Framework Core — model configuration, navigation properties, query translation differences, and migration history are all handled. We run EF6 and EF Core side-by-side against the same database and validate query output parity with automated comparison tests that execute the same business queries through both ORMs and diff the results. Domain models, DTOs, validation logic, and business rule libraries are ported to .NET Standard 2.0 where possible (consumed by both Framework and modern projects) or to .NET 8 where .NET Standard constraints are too limiting.
4. **API and Service Layer Migration (3-6 Weeks)** — Controllers, API endpoints, and background services are migrated module by module. Each module follows the same cycle: extract the bounded context into a new .NET 8 project, rewrite controllers from System.Web.Mvc or System.Web.Http to ASP.NET Core, replace WCF service references with gRPC clients or REST HttpClient calls, convert authentication middleware, wire up dependency injection using the built-in container, write integration tests that validate behavioral parity with the legacy implementation, deploy to staging behind YARP, run parallel traffic comparison (shadow mode) to verify identical responses, then flip the YARP route to send production traffic to the new service. Each module goes through this cycle independently. If a module has issues in production, the YARP route reverts to the legacy backend in seconds.
5. **UI Layer Migration and Legacy Decommission (2-4 Weeks)** — With all API endpoints and services running on .NET 8, the UI layer migrates last. Razor views are converted from the legacy view engine to ASP.NET Core Razor Pages or Blazor Server depending on the interactivity requirements. Bundling and minification pipelines are replaced with modern build tooling. JavaScript integrations are validated against the new backend. Once the UI layer is fully migrated and validated in production, the legacy .NET Framework application is decommissioned — all YARP routes now point to .NET 8 services, the IIS application pool is shut down, and the Windows Server instance can be replaced with Linux containers. Post-migration, we configure production monitoring with OpenTelemetry, set up health check endpoints for container orchestrators, and provide 30 days of hypercare support to catch any edge cases that surface under full production traffic.

---

## Frequently Asked Questions

### How long does a .NET Framework to .NET 8 migration take?

Timeline depends on solution size, dependency complexity, and the number of Windows-specific APIs your application uses. A focused web application with 50K-100K lines of code, standard MVC controllers, Entity Framework 6, and no WCF services typically takes 2-3 months from assessment to legacy decommission. A large enterprise monolith with 300K+ lines of code, multiple WCF services, Windows Services, COM interop, and deep System.Web dependencies takes 4-8 months. The strangler fig approach means you do not need to wait until the full migration is complete to see value — each module ships to production on .NET 8 as it finishes, and your team begins benefiting from improved performance, modern tooling, and cross-platform deployment incrementally. The most important variable is not lines of code but dependency entanglement — a 200K LOC solution with clean project boundaries migrates faster than a 80K LOC solution where every class references System.Web.HttpContext.

### Can we migrate incrementally or does it have to be all-at-once?

Incremental migration is the only approach FreedomDev recommends. The all-at-once rewrite — freeze features, rebuild everything, flip the switch on launch day — fails 60-80% of the time in practice. The strangler fig pattern with YARP reverse proxy lets you run both .NET Framework and .NET 8 simultaneously in production. YARP routes requests to the correct backend based on URL path, header, or other criteria. Each module is migrated independently: extract it into a .NET 8 project, validate behavioral parity, deploy behind YARP, flip the route. The legacy backend handles everything that has not been migrated yet. Your users never know a migration is happening. If a newly migrated module has issues, the YARP route reverts to the legacy implementation in seconds. This is the approach Microsoft recommends in their official migration documentation, and it is how every successful large-scale .NET migration we have seen has been executed.

### What happens to our WCF services?

WCF is the hardest part of most .NET Framework migrations because it does not exist in .NET 8. Microsoft deliberately chose not to port WCF server hosting to modern .NET. CoreWCF — the community-maintained partial port backed by AWS and Microsoft — supports BasicHttpBinding and NetTcpBinding for teams that need a bridge during migration, but it does not cover WS-Security, WS-ReliableMessaging, MSMQ bindings, or many WCF behaviors and inspectors. For internal service-to-service communication, the migration target is gRPC: binary Protocol Buffers serialization, HTTP/2 transport, bidirectional streaming, and strongly-typed generated clients. gRPC throughput on .NET 8 is substantially higher than WCF NetTCP, and the proto-file-first contract model catches breaking changes at compile time instead of runtime. For public-facing endpoints where consumers expect HTTP/JSON, the migration target is ASP.NET Core Web API with OpenAPI documentation. We convert WCF DataContracts to DTOs, ServiceContracts to controller actions or gRPC service definitions, and rebuild the service implementations against the ASP.NET Core hosting model.

### How do we handle Entity Framework 6 data access during migration?

EF6 and EF Core run side-by-side against the same database during the transition period. This is not a theoretical capability — it is how we execute every migration. The legacy modules that have not been migrated yet continue using EF6 against the production database. Newly migrated .NET 8 modules use EF Core against the same database. Both ORMs coexist because they operate at the application level, not the database level — the database does not know or care which ORM is generating the SQL. The migration itself requires careful attention to behavioral differences: EF Core defaults to no lazy loading (your code will break if it depended on transparent lazy navigation property loading), GroupBy translation was incomplete before EF Core 7, many-to-many join tables are implicit in EF Core instead of explicit, and the LINQ-to-SQL translation engine is completely different, meaning some EF6 queries produce different SQL or fail in EF Core. We validate with automated comparison tests that run identical business queries through both ORMs and diff the results at the row level.

### What about Windows-specific code — Windows Services, COM interop, WPF, WinForms?

Windows-specific dependencies fall into three categories. First, Windows Services that handle background processing migrate to the BackgroundService base class in .NET 8, which runs as a hosted service inside the ASP.NET Core host and deploys to Linux containers — no Windows dependency, no sc.exe installation, no separate project. Second, COM interop is trickier: if your application calls COM components (often legacy DLLs for hardware integration, reporting engines, or industry-specific tools), those calls can only run on Windows. The options are wrapping the COM dependency behind an API that runs on a Windows container while the rest of the application runs on Linux, replacing the COM component with a .NET-native alternative, or accepting that this specific service stays on Windows as a sidecar. Third, WinForms and WPF desktop applications: both are supported on .NET 8 but remain Windows-only. If cross-platform is a goal, Blazor Server or Blazor WebAssembly replaces the desktop UI with a browser-accessible application, or .NET MAUI targets Windows, macOS, iOS, and Android from a single codebase. The decision depends on whether your users need offline capability, hardware access, or other desktop-specific features.

### Will our existing NuGet packages work on .NET 8?

Some will, some will not, and some will work with caveats. Packages targeting .NET Standard 2.0 work on both .NET Framework 4.6.1+ and .NET 8 without changes — this is the bridge target that Microsoft designed for exactly this transition period. Packages that target .NET Framework directly (net45, net48, etc.) will not load in a .NET 8 project. Packages that have published .NET 8 targets (net8.0) will work with full platform support. The gray area is packages that technically load via .NET Standard compatibility but trigger platform compatibility analyzer warnings because they call APIs that behave differently or are missing on .NET 8. Our assessment phase includes a full package audit that categorizes every dependency: green (works as-is), yellow (works with warnings or behavioral changes), red (incompatible, replacement identified), and black (incompatible, custom replacement required). Common red-flag packages include anything depending on System.Web, System.Configuration.ConfigurationManager (replaced by Microsoft.Extensions.Configuration), and WCF client proxies (replaced by gRPC or REST clients).

### What does the .NET Upgrade Assistant actually do versus what we still need engineers for?

The .NET Upgrade Assistant automates mechanical transformations: converting .csproj project files from the legacy verbose format to SDK-style, switching from packages.config to PackageReference, updating target framework monikers, replacing known API calls with their .NET 8 equivalents where a 1:1 mapping exists, and generating a compatibility report listing every breaking change, missing API, and deprecated pattern in your codebase. It is genuinely useful as a starting point and saves several days of tedious file-format conversion. What it cannot do is the actual migration engineering. It cannot redesign WCF service architectures as gRPC services. It cannot rewrite System.Web.HttpContext usage patterns to ASP.NET Core's fundamentally different request pipeline. It cannot convert EF6 data models to EF Core with correct configuration for the behavioral differences. It cannot decide whether your Windows Service should become a BackgroundService, a Hangfire job, or a separate container. It cannot refactor Global.asax lifecycle hooks into middleware. It cannot determine the correct module extraction order for strangler fig migration. It cannot write the YARP route configuration. The Upgrade Assistant is a diagnostic and scaffolding tool. The migration itself requires engineers who understand both the legacy and modern platforms.

### How much does a .NET Framework to .NET 8 migration cost?

Cost scales with complexity, not just lines of code. A straightforward ASP.NET MVC application with 50K-100K lines of code, EF6 data access, no WCF, and clean project boundaries runs $40,000-$80,000 for the full migration including assessment, implementation, testing, and legacy decommission. Mid-complexity applications — 100K-300K lines of code, 2-5 WCF services, Windows Services, mixed EF6 and ADO.NET data access — run $80,000-$200,000. Large enterprise monoliths with 300K+ lines of code, deep System.Web entanglement, COM interop, multiple WCF service layers, and complex authentication run $200,000-$500,000+. The ROI calculation should include: Windows Server licensing eliminated ($1K-$6K per server per year), cloud compute cost reduction (30-50% from .NET 8 performance and Linux containers), developer productivity gains from modern tooling and language features, expanded hiring pool reducing recruitment costs, and reduced security risk from staying on a supported framework. Most organizations we work with see full payback within 12-18 months of completing the migration.

---

**Canonical URL**: https://freedomdev.com/solutions/dotnet-framework-to-dotnet8

_Last updated: 2026-05-12_