IIS and Windows Deployment — The ASP.NET Core Module

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>
Note: In-Process hosting runs the Kestrel server inside the IIS worker process (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.
Tip: When deploying to IIS, create a dedicated Application Pool for each ASP.NET Core application and set it to No Managed Code in the .NET CLR version setting. ASP.NET Core manages its own .NET runtime — IIS should not attempt to load a .NET Framework CLR alongside it. A pool configured with .NET CLR version set to a specific .NET Framework version can cause startup failures. Also disable all IIS authentication modules except Anonymous Authentication — ASP.NET Core handles its own authentication.
Warning: The ASP.NET Core Module (ANCM) must be installed on the server separately from the .NET runtime. Download the .NET Hosting Bundle from Microsoft — it includes the .NET Runtime, ASP.NET Core Runtime, and the ANCM in a single installer. Installing only the .NET Runtime or SDK is not sufficient for IIS deployments. The Hosting Bundle is the correct installer for Windows IIS servers. Verify the ANCM is installed by checking %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.

🧠 Test Yourself

What is the key functional difference between In-Process and Out-of-Process IIS hosting for ASP.NET Core?