The first decision that shapes a .NET 10 IIS deploy is not which CI runner you use—it is whether the package is framework-dependent (FDD) or self-contained (SCD). That choice sets folder size, cold-start cost, patch ownership, and whether the site will even start under a shared app pool.
On Windows shared and reseller hosts that already ship the .NET 10 runtime, FDD is almost always the right default. Self-contained earns its weight when you control the box and need a runtime band the machine does not have, or when you must freeze the exact bits that left your build agent. Everything else in the pipeline—Web Deploy, publish profiles, smoke checks—should follow that choice, not fight it.
#What FDD and SCD actually put on disk
FDD ships your assemblies plus deps.json and runtimeconfig.json. IIS loads the shared .NET 10 host and framework from the machine. SCD ships a private copy of the runtime and native host under your site root (or a RID-specific folder), so the app does not need a machine-wide install matching your target framework.
- FDD: small package, faster upload over Web Deploy, host owns security patches for the shared runtime.
- SCD: large package (often 70–120+ MB before your content), slower first sync, you own runtime updates until the next publish.
- Both still need the ASP.NET Core Module (ANCM) and a correct web.config for in-process or out-of-process IIS hosting.
#Publish settings that match shared IIS
For shared Windows hosting that lists .NET 10 GA, publish framework-dependent, portable (no RuntimeIdentifier), and prefer ReadyToRun only if you have measured a cold-start win. Leave SelfContained false so the build does not embed a private runtime the host will ignore or conflict with.
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<SelfContained>false</SelfContained>
<!-- omit RuntimeIdentifier for portable FDD -->
<PublishReadyToRun>false</PublishReadyToRun>
<PublishTrimmed>false</PublishTrimmed>
</PropertyGroup>
A matching .pubxml keeps CI honest. Point Web Deploy at the site or app path the control panel created, and avoid baking Production connection strings into the package—inject them on the server or via deploy-time parameters your host supports.
<Project>
<PropertyGroup>
<WebPublishMethod>MSDeploy</WebPublishMethod>
<SelfContained>false</SelfContained>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<ExcludeApp_Data>false</ExcludeApp_Data>
</PropertyGroup>
</Project>
#When self-contained is worth it on VPS
On a Windows VPS or dedicated box you administer, SCD is useful when the OS image lags your patch bar, when two apps must pin different runtime builds, or when you want the site to start even if someone removes a shared runtime feature pack. Pin a win-x64 RID, keep the app pool 64-bit, and plan disk growth—every release carries the runtime again unless you layer carefully.
- Set RuntimeIdentifier to win-x64 (or win-x86 only if the pool is forced 32-bit).
- Set SelfContained true; do not assume the machine-wide .NET 10 install will be used.
- Budget Web Deploy time and site quota; exclude logs, App_Data uploads, and web.config machine-specific bits you manage outside publish.
#Prove the host can run what you shipped
After the first FDD deploy, confirm the shared runtime before you declare victory. On a VPS you can query installed frameworks; on shared hosting, a minimal endpoint or the official runtime presence under the app pool identity is enough. Failures here look like 500.0/500.31 ANCM errors, not compile errors.
# On a VPS or dedicated host you manage:
dotnet --list-runtimes | Select-String "Microsoft.(AspNetCore|NETCore).App 10."
# Quick local publish check before Web Deploy:
dotnet publish .\src\Web\Web.csproj -c Release -o .\artifacts\web --self-contained false
Get-ChildItem .\artifacts\web\*.runtimeconfig.json
Then hit a cheap health or version route over HTTPS, confirm ASPNETCORE_ENVIRONMENT and the connection string source you expect, and watch the app pool for rapid fail protection after the swap. If you needed SCD, re-check disk use under the site root so the next release does not fill the volume.
Practical takeaway: default to framework-dependent .NET 10 publishes for IIS on hosts that already provide the runtime—including typical Windows shared layouts—and reserve self-contained win-x64 packages for machines you patch yourself or for hard runtime pins. Encode SelfContained and RID in the pubxml your CI uses, keep secrets off the build output, and verify ANCM plus a live request after every promote so the package mode you chose is the one that actually started.
Comments
No comments yet