IIS (Internet Information Services) remains the primary web server for ASP.NET Core deployments on Windows — in corporate environments, Windows Server infrastructure, and Azure App Service (which uses IIS internally). ASP.NET Core does not run natively inside IIS; instead, the ASP.NET Core Module (ANCM) acts as an IIS handler that either forwards requests to Kestrel in a separate process (Out-of-Process) or hosts the .NET runtime directly inside the IIS worker process (In-Process). Understanding both models and their trade-offs is essential for enterprise Windows deployments.
IIS Hosting Models
// ── web.config — IIS configuration for ASP.NET Core ──────────────────────
// This file is generated automatically by dotnet publish
// Edit it to configure the hosting model
// In-Process hosting (default in .NET 5+)
// ASP.NET Core runtime runs inside the IIS worker process (w3wp.exe)
// Faster — no inter-process communication overhead
// Less isolated — a crash affects IIS
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*"
modules="AspNetCoreModuleV2"
resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet"
arguments=".\BlogApp.Api.dll"
stdoutLogEnabled="false"
stdoutLogFile=".\logs\stdout"
hostingModel="inprocess"> <!-- or "outofprocess" -->
<environmentVariables>
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" />
<environmentVariable name="ConnectionStrings__Default"
value="Server=.;Database=BlogApp;..." />
</environmentVariables>
</aspNetCore>
</system.webServer>
</configuration>
w3wp.exe). It is faster because there is no inter-process communication, but a crash in Kestrel/your application can bring down the IIS worker. Out-of-Process hosting keeps IIS as a reverse proxy to a separate Kestrel process — crashes in Kestrel do not affect IIS, and IIS can automatically restart the Kestrel process. For high-stability requirements, Out-of-Process provides better isolation; for maximum performance, In-Process is the right choice and is the default in modern .NET.%windir%\system32\inetsrv\aspnetcore.dll.Web Deploy and CI Publishing
// ── Publish to IIS via Web Deploy from CLI ────────────────────────────────
dotnet publish -c Release -o ./publish
// Use msdeploy.exe (Web Deploy) to push to IIS
msdeploy.exe \
-verb:sync \
-source:contentPath=./publish \
-dest:contentPath="IIS Web Application Name",
computerName="https://server:8172/msdeploy.axd",
authType=NTLM
// ── Or use the Visual Studio publish profile ──────────────────────────────
// Create a .pubxml publish profile in Properties/PublishProfiles/
// Right-click project → Publish → Web Server (IIS) → Web Deploy
// ── IIS Application Pool — recommended settings ───────────────────────────
// .NET CLR Version: No Managed Code (ASP.NET Core manages its own CLR)
// Managed Pipeline Mode: Integrated
// Identity: ApplicationPoolIdentity or a dedicated service account
// Start Mode: AlwaysRunning (avoid cold start on first request)
// Idle Time-out: 0 (never stop due to inactivity)
Common Mistakes
Mistake 1 — Not installing the .NET Hosting Bundle (ANCM missing)
❌ Wrong — installing .NET Runtime instead of Hosting Bundle; IIS cannot load ANCM; 500.19 error.
✅ Correct — install the Hosting Bundle from the .NET download page; it includes ANCM.
Mistake 2 — Setting Application Pool to use a specific .NET Framework CLR version
❌ Wrong — IIS tries to load .NET Framework CLR for ASP.NET Core; startup fails or instability occurs.
✅ Correct — set .NET CLR Version to “No Managed Code” for all ASP.NET Core application pools.