{"id":952,"date":"2026-10-27T22:37:45","date_gmt":"2026-10-27T22:37:45","guid":{"rendered":"https:\/\/windows-vps.org\/blog\/?p=952"},"modified":"2026-10-27T22:37:45","modified_gmt":"2026-10-27T22:37:45","slug":"net-framework-4-8-vs-dotnet-8-lts-upgrade-iis-app-pool","status":"publish","type":"post","link":"https:\/\/windows-vps.org\/blog\/net-framework-4-8-vs-dotnet-8-lts-upgrade-iis-app-pool\/","title":{"rendered":".NET Framework 4.8 vs .NET 8 on IIS: Upgrading an ASP.NET App Pool"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">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.<\/p>\n\n\n<!-- wp:heading level=\"2\" -->\n<h2>Two Completely Different Hosting Models<\/h2>\n<!-- \/wp:post-content -->\n\n<!-- wp:paragraph -->\n<p>.NET Framework 4.8 runs in-process inside <code>w3wp.exe<\/code> through the classic ASP.NET ISAPI integration, hosting <code>System.Web<\/code>. The worker process loads the CLR, the AppDomain is created per application pool, and the application configuration comes from <code>web.config<\/code> combined with <code>machine.config<\/code>.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>ASP.NET Core (.NET 8\/10) has no dependency on <code>System.Web<\/code>. It runs as a standalone application host (<code>Kestrel<\/code>) 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 <code>dotnet.exe MyApp.dll<\/code> as a child process of <code>w3wp.exe<\/code> and forwards requests to it. Two hosting models with fundamentally different failure modes \u2014 which is why the error codes look different too.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:table -->\n<figure class=\"wp-block-table\"><table><thead><tr><th>Concern<\/th><th>.NET Framework 4.8<\/th><th>.NET 8 \/ .NET 10<\/th><\/tr><\/thead><tbody><tr><td>Runtime install<\/td><td>In-box on Server 2022\/2025<\/td><td>Hosting Bundle MSI, versioned side by side<\/td><\/tr><tr><td>Worker model<\/td><td>AppDomain inside w3wp<\/td><td>Separate dotnet.exe process per app<\/td><\/tr><tr><td>Config<\/td><td>web.config<\/td><td>appsettings.json + environment variables<\/td><\/tr><tr><td>Session state<\/td><td>InProc, StateServer, SQL Server<\/td><td>Redis, SQL, or custom; no InProc equivalent<\/td><\/tr><tr><td>Compilation<\/td><td>JIT or precompiled<\/td><td>ReadyToRun or AOT optional<\/td><\/tr><tr><td>Cross-platform<\/td><td>Windows only<\/td><td>Windows\/Linux\/macOS<\/td><\/tr><\/tbody><\/table><\/figure>\n<!-- \/wp:table -->\n\n<!-- wp:heading level=\"2\" -->\n<h2>What Breaks First: The .NET Portability Report<\/h2>\n<!-- \/wp:heading -->\n\n<!-- wp:paragraph -->\n<p>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:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:list -->\n<ul><li><strong>System.Web.<\/strong> Everything from <code>HttpContext.Current<\/code>, <code>HttpRuntime<\/code>, <code>HttpServerUtility<\/code>, <code>HttpResponse.Filter<\/code>, to <code>BundleConfig<\/code>. There is no shim on .NET Core; these are the porting work.<\/li><li><strong>Web Forms.<\/strong> Not supported. If the app has <code>.aspx<\/code> pages with server controls, the migration is a rewrite, not a port. Do not attempt a business case that says otherwise.<\/li><li><strong>Windows Communication Foundation server-side.<\/strong> WCF client support exists in .NET Core via <code>System.ServiceModel<\/code> packages; server-side hosting does not. Replace with gRPC or a minimal API.<\/li><li><strong>AppDomain.<\/strong> <code>AppDomain.CreateDomain<\/code> is not supported. Plugin hosting that relied on domain isolation needs an AssemblyLoadContext-based redesign.<\/li><li><strong>Windows Authentication via IIS.<\/strong> Works, but the configuration moves from <code>system.web\/authentication<\/code> to <code>Microsoft.AspNetCore.Authentication.Negotiate<\/code> and requires Windows Authentication enabled on the IIS feature.<\/li><\/ul>\n<!-- \/wp:list -->\n\n<!-- wp:heading level=\"2\" -->\n<h2>Running Both Runtimes on One Host<\/h2>\n<!-- \/wp:heading -->\n\n<!-- wp:paragraph -->\n<p>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.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code># Features needed on Server 2022\/2025\nInstall-WindowsFeature Web-Server, Web-Asp-Net45, Web-Windows-Auth, Web-Mgmt-Console\n\n# The Hosting Bundle is installed via MSI, not a Windows feature\n# aspnetcore-runtime-10.0.x-win-x64.exe + dotnet-hosting-10.0.x-win.exe\ndotnet --list-runtimes\n\n# After install, restart IIS so the ANCM registers\niisreset<\/code><\/pre>\n<!-- \/wp:code -->\n\n<!-- wp:paragraph -->\n<p>A side-by-side application pool scheme that survives releases looks like this: the Framework app stays on pool <code>LegacyPool<\/code> with <code>managedRuntimeVersion=v4.0<\/code> and a fixed daily recycle; the new app lives on pool <code>CorePool<\/code> with <code>managedRuntimeVersion=\"\"<\/code> (no managed runtime) and <code>startMode=\"AlwaysRunning\"<\/code>. 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.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code>New-WebAppPool -Name \"CorePool\"\nSet-ItemProperty IIS:\\AppPools\\CorePool -Name managedRuntimeVersion -Value \"\"\nSet-ItemProperty IIS:\\AppPools\\CorePool -Name startMode -Value \"AlwaysRunning\"\nSet-ItemProperty IIS:\\AppPools\\CorePool -Name \"processModel.identityType\" -Value \"ApplicationPoolIdentity\"\n\nNew-WebApplication -Site \"Default Web Site\" -Name \"app2\" `\n  -PhysicalPath \"C:\\sites\\app2\" -ApplicationPool \"CorePool\"<\/code><\/pre>\n\n\n<!-- wp:heading level=\"2\" -->\n<h2>Performance: What You Actually Gain<\/h2>\n<!-- \/wp:heading -->\n\n<!-- wp:paragraph -->\n<p>The measurable differences on a modest IIS host (4 vCPU, 8 GB) are real but narrower than the marketing suggests:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:list -->\n<ul><li><strong>Startup time.<\/strong> 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.<\/li><li><strong>Throughput per core.<\/strong> Request throughput on JSON APIs typically improves 15-40% on Core vs Framework at the same hardware, mostly from <code>Span&lt;T&gt;<\/code>, pooled buffers, and the async pipeline. Static file serving goes through IIS in both cases, so the delta is negligible there.<\/li><li><strong>Memory.<\/strong> 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.<\/li><li><strong>Patch cadence.<\/strong> 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.<\/li><\/ul>\n<!-- \/wp:list -->\n\n<!-- wp:paragraph -->\n<p>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 <a href=\"https:\/\/windows-vps.org\/\">Windows Server plans at windows-vps.org<\/a> list RAM and NVMe IOPS per tier, and the <a href=\"https:\/\/windows-vps.org\/blog\/iis-application-pool-memory-limits-aspnet-core\/\">application pool memory limits guide<\/a> covers how to bound the process so a leak on one app does not take the host down.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:heading level=\"2\" -->\n<h2>A Decision Rule That Holds Up<\/h2>\n<!-- \/wp:heading -->\n\n<!-- wp:paragraph -->\n<p>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.<\/p>\n<!-- \/wp:paragraph -->\n","protected":false},"excerpt":{"rendered":"<p>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 &#8230; <a title=\".NET Framework 4.8 vs .NET 8 on IIS: Upgrading an ASP.NET App Pool\" class=\"read-more\" href=\"https:\/\/windows-vps.org\/blog\/net-framework-4-8-vs-dotnet-8-lts-upgrade-iis-app-pool\/\" aria-label=\"Read more about .NET Framework 4.8 vs .NET 8 on IIS: Upgrading an ASP.NET App Pool\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":1,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-952","post","type-post","status-publish","format-standard","hentry","category-reviews"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>.NET Framework 4.8 vs .NET 8 on IIS: Upgrading an ASP.NET App Pool - Windows VPS Blog<\/title>\n<meta name=\"description\" content=\"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\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/windows-vps.org\/blog\/net-framework-4-8-vs-dotnet-8-lts-upgrade-iis-app-pool\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\".NET Framework 4.8 vs .NET 8 on IIS: Upgrading an ASP.NET App Pool\" \/>\n<meta property=\"og:description\" content=\".NET Framework 4.8 vs .NET 8 on IIS: Upgrading an ASP.NET App Pool\" \/>\n<meta property=\"og:url\" content=\"https:\/\/windows-vps.org\/blog\/net-framework-4-8-vs-dotnet-8-lts-upgrade-iis-app-pool\/\" \/>\n<meta property=\"og:site_name\" content=\"Windows VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-27T22:37:45+00:00\" \/>\n<meta name=\"author\" content=\"windows-vps\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@myxiechengxuan\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"windows-vps\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/windows-vps.org\/blog\/net-framework-4-8-vs-dotnet-8-lts-upgrade-iis-app-pool\/\",\"url\":\"https:\/\/windows-vps.org\/blog\/net-framework-4-8-vs-dotnet-8-lts-upgrade-iis-app-pool\/\",\"name\":\".NET Framework 4.8 vs .NET 8 on IIS: Upgrading an ASP.NET App Pool - Windows VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/windows-vps.org\/blog\/#website\"},\"datePublished\":\"2026-10-27T22:37:45+00:00\",\"author\":{\"@id\":\"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58\"},\"description\":\"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\",\"breadcrumb\":{\"@id\":\"https:\/\/windows-vps.org\/blog\/net-framework-4-8-vs-dotnet-8-lts-upgrade-iis-app-pool\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/windows-vps.org\/blog\/net-framework-4-8-vs-dotnet-8-lts-upgrade-iis-app-pool\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/windows-vps.org\/blog\/net-framework-4-8-vs-dotnet-8-lts-upgrade-iis-app-pool\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/windows-vps.org\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\".NET Framework 4.8 vs .NET 8 on IIS: Upgrading an ASP.NET App Pool\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/windows-vps.org\/blog\/#website\",\"url\":\"https:\/\/windows-vps.org\/blog\/\",\"name\":\"Windows VPS Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/windows-vps.org\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58\",\"name\":\"windows-vps\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/3f2573db5afcd1a6ab9abcc5d48fc8e42584bc87ab9d98cc156e5b2097766dd9?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/3f2573db5afcd1a6ab9abcc5d48fc8e42584bc87ab9d98cc156e5b2097766dd9?s=96&d=mm&r=g\",\"caption\":\"windows-vps\"},\"sameAs\":[\"https:\/\/windows-vps.org\/blog\",\"https:\/\/x.com\/myxiechengxuan\"],\"url\":\"https:\/\/windows-vps.org\/blog\/author\/myxiechengxuan\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":".NET Framework 4.8 vs .NET 8 on IIS: Upgrading an ASP.NET App Pool - Windows VPS Blog","description":"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","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/windows-vps.org\/blog\/net-framework-4-8-vs-dotnet-8-lts-upgrade-iis-app-pool\/","og_locale":"en_US","og_type":"article","og_title":".NET Framework 4.8 vs .NET 8 on IIS: Upgrading an ASP.NET App Pool","og_description":".NET Framework 4.8 vs .NET 8 on IIS: Upgrading an ASP.NET App Pool","og_url":"https:\/\/windows-vps.org\/blog\/net-framework-4-8-vs-dotnet-8-lts-upgrade-iis-app-pool\/","og_site_name":"Windows VPS Blog","article_published_time":"2026-10-27T22:37:45+00:00","author":"windows-vps","twitter_card":"summary_large_image","twitter_creator":"@myxiechengxuan","twitter_misc":{"Written by":"windows-vps","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/windows-vps.org\/blog\/net-framework-4-8-vs-dotnet-8-lts-upgrade-iis-app-pool\/","url":"https:\/\/windows-vps.org\/blog\/net-framework-4-8-vs-dotnet-8-lts-upgrade-iis-app-pool\/","name":".NET Framework 4.8 vs .NET 8 on IIS: Upgrading an ASP.NET App Pool - Windows VPS Blog","isPartOf":{"@id":"https:\/\/windows-vps.org\/blog\/#website"},"datePublished":"2026-10-27T22:37:45+00:00","author":{"@id":"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58"},"description":"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","breadcrumb":{"@id":"https:\/\/windows-vps.org\/blog\/net-framework-4-8-vs-dotnet-8-lts-upgrade-iis-app-pool\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/windows-vps.org\/blog\/net-framework-4-8-vs-dotnet-8-lts-upgrade-iis-app-pool\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/windows-vps.org\/blog\/net-framework-4-8-vs-dotnet-8-lts-upgrade-iis-app-pool\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/windows-vps.org\/blog\/"},{"@type":"ListItem","position":2,"name":".NET Framework 4.8 vs .NET 8 on IIS: Upgrading an ASP.NET App Pool"}]},{"@type":"WebSite","@id":"https:\/\/windows-vps.org\/blog\/#website","url":"https:\/\/windows-vps.org\/blog\/","name":"Windows VPS Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/windows-vps.org\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/44caceed916d0db318aa08d5623a7a58","name":"windows-vps","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/windows-vps.org\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/3f2573db5afcd1a6ab9abcc5d48fc8e42584bc87ab9d98cc156e5b2097766dd9?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/3f2573db5afcd1a6ab9abcc5d48fc8e42584bc87ab9d98cc156e5b2097766dd9?s=96&d=mm&r=g","caption":"windows-vps"},"sameAs":["https:\/\/windows-vps.org\/blog","https:\/\/x.com\/myxiechengxuan"],"url":"https:\/\/windows-vps.org\/blog\/author\/myxiechengxuan\/"}]}},"_links":{"self":[{"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/posts\/952","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/comments?post=952"}],"version-history":[{"count":1,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/posts\/952\/revisions"}],"predecessor-version":[{"id":953,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/posts\/952\/revisions\/953"}],"wp:attachment":[{"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/media?parent=952"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/categories?post=952"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/windows-vps.org\/blog\/wp-json\/wp\/v2\/tags?post=952"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}