.NET Framework 4.8 vs .NET 8 on IIS: Upgrading an ASP.NET App Pool

You have an ASP.NET application running on .NET Framework 4.8 under IIS. It works, it is stable, and it has been in production since Server 2012. The question is whether to move it to .NET 8 or .NET 10 on a current Windows Server host. The honest answer is that many of these apps should not be migrated at all, and the ones that should are usually decided by a small number of hard constraints: Windows-only dependencies, third-party libraries without .NET Core builds, and whether the team can afford a full regression cycle. This guide covers what actually changes under the hood, what will break, and how to run both runtimes side by side on the same IIS host while you decide.

Two Completely Different Hosting Models

.NET Framework 4.8 runs in-process inside w3wp.exe through the classic ASP.NET ISAPI integration, hosting System.Web. The worker process loads the CLR, the AppDomain is created per application pool, and the application configuration comes from web.config combined with machine.config.

ASP.NET Core (.NET 8/10) has no dependency on System.Web. It runs as a standalone application host (Kestrel) that IIS fronts via the ASP.NET Core Module V2. IIS is now a reverse proxy plus a process manager, not a runtime host. The ANCM launches dotnet.exe MyApp.dll as a child process of w3wp.exe and forwards requests to it. Two hosting models with fundamentally different failure modes — which is why the error codes look different too.

Concern.NET Framework 4.8.NET 8 / .NET 10
Runtime installIn-box on Server 2022/2025Hosting Bundle MSI, versioned side by side
Worker modelAppDomain inside w3wpSeparate dotnet.exe process per app
Configweb.configappsettings.json + environment variables
Session stateInProc, StateServer, SQL ServerRedis, SQL, or custom; no InProc equivalent
CompilationJIT or precompiledReadyToRun or AOT optional
Cross-platformWindows onlyWindows/Linux/macOS

What Breaks First: The .NET Portability Report

Before any code changes, install the .NET Upgrade Assistant and the API Portability Analyzer and run them against the solution. The report lists the APIs in use that have no direct .NET Core equivalent. The recurring offenders on a typical ASP.NET MVC app:

  • System.Web. Everything from HttpContext.Current, HttpRuntime, HttpServerUtility, HttpResponse.Filter, to BundleConfig. There is no shim on .NET Core; these are the porting work.
  • Web Forms. Not supported. If the app has .aspx pages with server controls, the migration is a rewrite, not a port. Do not attempt a business case that says otherwise.
  • Windows Communication Foundation server-side. WCF client support exists in .NET Core via System.ServiceModel packages; server-side hosting does not. Replace with gRPC or a minimal API.
  • AppDomain. AppDomain.CreateDomain is not supported. Plugin hosting that relied on domain isolation needs an AssemblyLoadContext-based redesign.
  • Windows Authentication via IIS. Works, but the configuration moves from system.web/authentication to Microsoft.AspNetCore.Authentication.Negotiate and requires Windows Authentication enabled on the IIS feature.

Running Both Runtimes on One Host

You do not need a separate server to trial the migration. IIS can host a .NET Framework app pool and an ASP.NET Core app pool on the same site, differentiated by application path or host header. The prerequisites are the IIS features for ASP.NET 4.x and the ASP.NET Core 10 Hosting Bundle installed on the same machine.

# Features needed on Server 2022/2025
Install-WindowsFeature Web-Server, Web-Asp-Net45, Web-Windows-Auth, Web-Mgmt-Console

# The Hosting Bundle is installed via MSI, not a Windows feature
# aspnetcore-runtime-10.0.x-win-x64.exe + dotnet-hosting-10.0.x-win.exe
dotnet --list-runtimes

# After install, restart IIS so the ANCM registers
iisreset

A side-by-side application pool scheme that survives releases looks like this: the Framework app stays on pool LegacyPool with managedRuntimeVersion=v4.0 and a fixed daily recycle; the new app lives on pool CorePool with managedRuntimeVersion="" (no managed runtime) and startMode="AlwaysRunning". Both can serve on the same IP with different host headers, so traffic can be shifted gradually at the load balancer rather than in a single cutover window.

New-WebAppPool -Name "CorePool"
Set-ItemProperty IIS:\AppPools\CorePool -Name managedRuntimeVersion -Value ""
Set-ItemProperty IIS:\AppPools\CorePool -Name startMode -Value "AlwaysRunning"
Set-ItemProperty IIS:\AppPools\CorePool -Name "processModel.identityType" -Value "ApplicationPoolIdentity"

New-WebApplication -Site "Default Web Site" -Name "app2" `
  -PhysicalPath "C:\sites\app2" -ApplicationPool "CorePool"

Performance: What You Actually Gain

The measurable differences on a modest IIS host (4 vCPU, 8 GB) are real but narrower than the marketing suggests:

  • Startup time. A Framework app warms in 1-3 seconds after a recycle once the ASP.NET temporary files are compiled. A Core app with ReadyToRun and Application Initialization warms in 400-800 ms. Repeat cold starts without ReadyToRun can be worse than Framework.
  • Throughput per core. Request throughput on JSON APIs typically improves 15-40% on Core vs Framework at the same hardware, mostly from Span<T>, pooled buffers, and the async pipeline. Static file serving goes through IIS in both cases, so the delta is negligible there.
  • Memory. A Core app process runs 150-350 MB working set for a typical API. A Framework app in a fresh pool runs 200-400 MB, higher after several app domain reloads.
  • Patch cadence. The Hosting Bundle is a separate monthly patch, and it does not install itself. A server can be fully patched at the OS level and be running a Hosting Bundle with a known vulnerability.

One thing that does not change: the underlying host still determines whether the workload is comfortable. A Core app is not lighter on disk I/O or SQL Server connections than its Framework predecessor; if the site was slow because it was on an undersized instance, the migration will not fix that. Match the runtime choice to a plan sized for the actual working set. The Windows Server plans at windows-vps.org list RAM and NVMe IOPS per tier, and the application pool memory limits guide covers how to bound the process so a leak on one app does not take the host down.

A Decision Rule That Holds Up

Migrate if the app is MVC or Web API, has no Web Forms views, no WCF server hosting, and no ISAPI dependencies. Stay on .NET Framework 4.8 if any of those three is present and the app is not growing. In both cases, rebuild on Windows Server 2022 or 2025 rather than staying on 2016 or 2019, and set the Hosting Bundle version as an explicit line item in the patch process so it cannot silently drift.

Leave a Comment