ASP.NET Core 10 is the current LTS runtime, and on Windows Server the default path is still in-process hosting under IIS 10.0 with the ASP.NET Core Module V2. Treat the hosting bundle, app pool identity, and Web.config as optional and you will see 502.5 startup failures, recycle storms, and SQL timeouts before your first controller runs.
This is the short checklist we use when a .NET 10 site lands on shared or Windows VPS IIS: match the bundle, lock the pool, pin the hosting model, and make connection strings survive recycle. No cloud-native digression—just the floor-level settings that keep apps up.
#Match the hosting bundle to the TFM
Framework-dependent publishes need the ASP.NET Core 10 Hosting Bundle on the machine. The bundle installs the runtime, shared framework, and ANCM V2. A site targeting net10.0 against an older bundle fails at startup with a generic 502.5; stdout logs (when enabled) usually name the missing framework version. Self-contained publishes avoid the shared runtime but still need ANCM and a correct processPath in Web.config.
After install, recycle the app pool—not only iisreset—so worker processes pick up the new module registration. On multi-site boxes, confirm no leftover aspnetcorev2.dll from older bundles is shadowing the path IIS loads.
#App pool settings that prevent thrash
ASP.NET Core does not use the .NET Framework CLR inside w3wp. Mis-set pools are the most common source of silent failures on shared Windows hosts.
- Managed pipeline mode: Integrated; .NET CLR version: No Managed Code.
- Start Mode: AlwaysRunning only if you accept the memory cost and the host allows it; otherwise leave OnDemand and fix cold-start with a lightweight warmup path.
- Identity: ApplicationPoolIdentity or a dedicated low-privilege domain/local account that can read the site folder and open outbound SQL. Grant that identity modify on your App_Data or logs folder if you write files.
- Idle timeout and regular recycle: keep defaults unless you have sticky in-memory state. Prefer external cache or SQL for session-like data so a recycle is boring.
Quick pool create for a dedicated site (run elevated):
Import-Module WebAdministration
New-WebAppPool -Name "MyAppPool"
Set-ItemProperty IIS:\AppPools\MyAppPool -Name managedRuntimeVersion -Value ""
Set-ItemProperty IIS:\AppPools\MyAppPool -Name managedPipelineMode -Value Integrated
Set-ItemProperty IIS:\AppPools\MyAppPool -Name processModel.identityType -Value ApplicationPoolIdentity
#Web.config: pin in-process and logging
Publish output should include a Web.config that sets hostingModel to inprocess. Out-of-process still works, but in-process removes the reverse-proxy hop, keeps Windows auth simpler, and is what most IIS shared environments expect. Enable stdout only while diagnosing; leave it off in production and rely on your ILogger providers.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*"
modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet"
arguments=".\MyApp.dll"
stdoutLogEnabled="false"
stdoutLogFile=".\logs\stdout"
hostingModel="inprocess">
<environmentVariables>
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" />
</environmentVariables>
</aspNetCore>
</system.webServer>
</location>
</configuration>
If the site is self-contained, processPath becomes the exe name and arguments can be empty. Keep inheritInChildApplications false so nested apps do not inherit a broken handler map. After Web Deploy, confirm the file on disk still has hostingModel="inprocess"—some older publish profiles rewrote it.
#SQL connection strings that survive recycle
IIS recycles will drop pooled connections. Use Microsoft.Data.SqlClient (current package line with .NET 10), enable connection resiliency in EF Core or your retry strategy, and avoid baking passwords into source. Prefer environment variables or the host’s secret store mapped into the aspNetCore environmentVariables section, then read them with standard configuration.
// Program.cs — minimal resilient SQL registration
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(
builder.Configuration.GetConnectionString("Default"),
sql => sql.EnableRetryOnFailure(
maxRetryCount: 5,
maxRetryDelay: TimeSpan.FromSeconds(10),
errorNumbersToAdd: null)));
On Windows hosting the connection string typically points at a SQL Server instance (2022 is still the common shared footprint) with Encrypt set appropriately for the certificate story on that box. Do not disable encryption casually; fix trust with a proper cert or a host-supported TrustServerCertificate policy only when you understand the network boundary.
#Deploy and verify
Web Deploy (MSDeploy) remains the straightforward path for IIS shared and many VPS setups: publish profile with the correct site name, app pool, and skip rules for logs. After sync, hit a lightweight health endpoint, confirm the app pool stayed in the Running state, and check that Event Viewer → Application has no ANCM or runtime load errors. If you use Windows Authentication, in-process plus the pool identity (or constrained delegation setup) is far less painful than out-of-process.
Practical takeaway: before you chase application bugs on a fresh .NET 10 deploy, verify four things in order—(1) Hosting Bundle matches net10.0, (2) app pool is No Managed Code, (3) Web.config has hostingModel="inprocess" and a valid processPath, (4) SQL client retry is on and the pool identity can open the database. Fix those and most “it works on my box” IIS failures disappear, leaving you with ordinary application logs instead of module mysteries.
Comments
No comments yet