BuildTools.WinApp: auto-install framework MSIX before dotnet run#531
Draft
yeelam-gordon wants to merge 1 commit into
Draft
BuildTools.WinApp: auto-install framework MSIX before dotnet run#531yeelam-gordon wants to merge 1 commit into
yeelam-gordon wants to merge 1 commit into
Conversation
The BuildTools.WinApp targets currently intercept `dotnet run` for
packaged apps and route execution through `winapp run`. However,
neither layer installs the WinAppSDK framework MSIX that the app's
AppxManifest depends on, so `dotnet run` fails on a clean machine
with 0x80073CF3:
"Windows cannot install package ... because this package depends
on a framework that could not be found. Provide the framework
'Microsoft.WindowsAppRuntime.N' ... to install."
The framework MSIX is already shipped inside the
Microsoft.WindowsAppSDK.Runtime NuGet (tools\MSIX\win10-{arch}\) and
exposed to MSBuild as @(AppxPackageRegistration) items via
buildTransitive\Microsoft.WindowsAppSDK.AppXReference.props -- the
same item group Visual Studio Deploy consumes. We just weren't
reading it.
This change adds a new `_WinAppInstallFrameworkDependencies` target
that:
* runs before _WinAppBuildRunArgs (and therefore before
_WinAppPrepareRunArguments and RunPackagedApp)
* filters @(AppxPackageRegistration) to entries whose Architecture
metadata matches the current $(Platform)
* shells out to `powershell -Command Add-AppxPackage` with a
Get-AppxPackage precheck so already-installed frameworks no-op
After this patch, `winapp init && dotnet run` truly works end-to-end
on a clean box -- no WindowsAppRuntimeInstall.exe and no
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
workaround required.
Empirical verification (HelloWinUI scaffolded from `dotnet new winui`,
depending on Microsoft.WindowsAppRuntime.2 v2.0.1.0, on a machine
without that framework installed):
Before: winapp run -> exit 1, "package depends on a framework
that could not be found".
Manual Add-AppxPackage of the MSIX from the NuGet cache, then
re-run: winapp run -> exit 0, AUMID + PID returned, app launched.
Follow-ups (not in this PR):
* Promote the inline powershell Exec to a `winapp install-package
<msix> [--if-missing]` subcommand
(PackageRegistrationService.InstallPackageAsync already exists
in the CLI source -- just needs a CLI surface).
* Consider iterating Main / Singleton MSIXes from
tools\MSIX\win10-<arch>\ for full parity with VS Deploy.
* Update docs/dotnet-run-support.md "Production Blockers" --
framework runtime provisioning is no longer a blocker.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
Build Metrics ReportBinary Sizes
Test Results✅ 993 passed, 1 skipped out of 994 tests in 429.6s (-20.6s vs. baseline) Test Coverage❌ 23.7% line coverage, 39.8% branch coverage · ✅ no change vs. baseline CLI Startup Time43ms median (x64, Updated 2026-05-12 00:29:55 UTC · commit |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The
Microsoft.Windows.SDK.BuildTools.WinApptargets currently interceptdotnet runfor packaged apps and route execution throughwinapp run(via_WinAppPrepareRunArgumentshookingComputeRunArguments). However, neither layer installs the WinAppSDK framework MSIX that the app''sAppxManifest.xmldepends on. On a clean machine,dotnet runtherefore fails atPackageManager.RegisterPackageAsyncinsidePackageRegistrationService.RegisterLooseLayoutAsyncwith0x80073CF3:Users are then forced to fall back to:
WindowsAppRuntimeInstall-x64.exemanually, or<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>and accepting the size cost.Neither matches the "
winapp init && dotnet runjust works" UX the support doc promises.Root cause
The framework MSIX is already in the user''s NuGet cache.
Microsoft.WindowsAppSDK.Runtimeships the framework MSIXes at:…and exposes them to MSBuild as
@(AppxPackageRegistration)items viabuildTransitive/Microsoft.WindowsAppSDK.AppXReference.props. That is the same item group Visual Studio''s Deploy action consumes — it''s why F5 in VS doesn''t need a separate runtime install. We just weren''t reading it.Fix
Add a new
_WinAppInstallFrameworkDependenciestarget that:_WinAppBuildRunArgs(and therefore before both_WinAppPrepareRunArgumentsfordotnet runandRunPackagedAppfor the standalone target),@(AppxPackageRegistration)to entries whoseArchitecturemetadata matches the current$(Platform)(lower-cased),powershell -Command Add-AppxPackagewith aGet-AppxPackageprecheck so already-installed frameworks no-op.Total change: +48 / -1 in one file.
Scope clarification — we install the framework MSIX only, by design
The Runtime NuGet ships four MSIXes per architecture:
Microsoft.WindowsAppRuntime.{N}.msix(the framework),.Main.{N}.msix,.DDLM.{N}.msix, and.Singleton.{N}.msix. This patch installs only the framework, and that is deliberate:AppxManifest.xmldeclares<PackageDependency Name="Microsoft.WindowsAppRuntime.N"/>— never Main/DDLM/Singleton.Add-AppxPackage -Registeronly fails when a<PackageDependency>can''t be resolved. Missing Main/DDLM/Singleton does not cause registration failure.WindowsAppRuntimeInstall.exe, not for app activation.<AppxPackageRegistration>inAppXReference.props. We follow the NuGet''s own contract — installing the siblings would be an unsolicited surprise install on the user''s machine and is not what VS Deploy does either.Empirical verification
Scaffolded
dotnet new winui -n HelloWinUIagainst a machine where the matching framework was not registered (verified viaGet-AppxPackage -Name Microsoft.WindowsAppRuntime.N).Before (without this patch):
After installing the framework MSIX from the NuGet cache (which is exactly what this patch automates):
App launched successfully.
Reproducing locally
If you want to repro on a dev box, you have to first remove whatever is pinning the framework. On most dev machines that is a Store-managed Main package. Working repro shape:
Easier alternative: spin up a fresh Windows VM or a
windows-latestGitHub Actions runner — those don''t have the Store pinning packages preinstalled.Implementation choice — inline PowerShell vs. new CLI command
I went with inline
powershell -Command Add-AppxPackagebecause it ships today without any CLI changes. A cleaner long-term shape is a newwinapp install-package <msix> [--if-missing]subcommand, sincePackageRegistrationService.InstallPackageAsyncalready exists in the source — it just needs a CLI surface. Happy to follow up with that as a separate PR if maintainers prefer that direction; let me know and I''ll swap the<Exec>over.Caveats
_WinAppValidateRunSupport).$(Platform)is one ofx86 / x64 / ARM64 / arm64ec(lower-cased to match the item metadata).AnyCPUis already rejected upstream by the MSIX targets (APPX0504), so no extra guard is needed here.MicrosoftWindowsAppSDKFoundationAppXVersion.props), so users always get the exact framework build the NuGet was authored against.Doc follow-up (not in this PR)
docs/dotnet-run-support.md"Production Blockers" section doesn''t list framework provisioning as a gap today. Worth an update after this lands.Marked as draft for maintainer review of the implementation choice (inline PowerShell vs. promote to CLI command) before final review.