Microsoft.Build.MsixPackaging — reusable MSBuild SDK for multi-app MSIX packaging#672
Open
shmuelie wants to merge 7 commits into
Open
Microsoft.Build.MsixPackaging — reusable MSBuild SDK for multi-app MSIX packaging#672shmuelie wants to merge 7 commits into
shmuelie wants to merge 7 commits into
Conversation
New MSBuild SDK that packages multiple .NET projects into a single sideloadable MSIX using per-project AppxFragment.xml manifest merging. Replaces WAP/DesktopBridge with a transparent, SDK-style workflow. Includes: - 3 compiled MSBuild tasks (netstandard2.0): - MergeAppxFragments: multi-section fragment merge + version/arch stamping - ValidateAppxManifest: XML well-formedness + required elements + duplicate IDs - FindWindowsSdkTool: locates MakeAppx/SignTool/MakePri from Windows SDK - Sdk.props: imports NoTargets, defines 19 configurable properties - Sdk.targets: BuildMsix orchestrator with 7-stage pipeline + 4 opt-in targets - VS Property Page (XAML Rule) with 10 properties across 4 categories - build/ files for traditional NuGet package consumption Ported from SEnglard Ideas/MsixPackagingSdk prototype and adapted to MSBuildSdks repo conventions (Microsoft.Build.* naming, central package management, signing, Nerdbank.GitVersioning). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
15 xunit tests covering the 3 compiled MSBuild tasks: - MergeAppxFragmentsTests: version validation, structured fragment detection, Identity attribute patching, indentation formatting - ValidateAppxManifestTests: valid manifest, missing Identity, duplicate Application IDs, malformed XML, missing file, invalid version - FindWindowsSdkToolTests: host architecture detection All tests pass across net472, net8.0, net9.0, and net10.0. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Minimal consumer project demonstrating the SDK: - SampleConsoleApp: trivial console app with AppxFragment.xml - SamplePackaging.msbuildproj: imports SDK from source tree - Package.base.appxmanifest: manifest template with fragment marker - Directory.Build.props: overrides task assembly path for local dev Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
MergeAppxFragments.cs and ValidateAppxManifest.cs had StyleCop violations (missing file headers, using order, omitted braces, member ordering, blank lines) that were masked by incremental analyzer caching and only surfaced on a clean build. Rewrap to satisfy the analyzers with no behavioral change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… signing Replace the SDK's hand-rolled Windows SDK tool discovery and the raw Exec calls to MakeAppx/SignTool with the compiled MSBuild tasks from the Microsoft.Windows.SDK.BuildTools.MSIX package (namespace Microsoft.Build.Msix): - Tool discovery: FindWindowsSdkTool (custom C# task) -> WinAppSdkGetSdkFileFullPath, used to locate MakeAppx.exe, SignTool.exe, and MakePri.exe. - Packing: PackMsix Exec(makeappx /d) -> WinAppSdkMakeAppxPack, packing from a generated [Files] mapping file built from the layout directory. - Signing: SignMsix Exec(signtool) -> WinAppSdkSignAppxPackage (adds timestamp and Azure Code Signing / Key Vault support). Integration (no bundling): the package is injected as a package reference from Sdk.props with GeneratePathProperty and ExcludeAssets=build;buildTransitive, so only the task assembly is used and the package's heavyweight WinAppSDK pipeline is not imported. VersionOverride is used under Central Package Management so no central PackageVersion entry is required. The task assembly is resolved per runtime (net6.0 for Core, net472 for desktop MSBuild). A small RoslynCodeTaskFactory inline task resolves the latest installed Windows SDK version for TargetPlatformVersion (honoring MsixWindowsSdkVersion when set). Removes FindWindowsSdkTool and its unit test. New properties: MsixSdkBuildToolsVersion, MsixWindowsSdkVersion, MsixHashAlgorithmId. MsixToolArchitecture is now a no-op (architecture resolved by the package). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The sample packaging project was nested a level too deep, so its SDK imports, ProjectReference, and default Package.base.appxmanifest/Images paths did not resolve (the project was never built in the original change). Flatten it to samples/MsixPackaging/ to match the sibling manifest, images, and app project, and point the dev-time _MsixSdkTasksAssembly at the artifacts output. Verified end-to-end: the sample now publishes, merges fragments, validates, and packs a valid .msix via the new build-tools pipeline. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.
Summary
New SDK project: Microsoft.Build.MsixPackaging — a reusable MSBuild SDK that packages multiple .NET projects into a single sideloadable MSIX using per-project
AppxFragment.xmlmanifest entries. Replaces WAP/DesktopBridge with a transparent, SDK-style workflow.SDK-tool discovery, MSIX packing, and signing use the compiled MSBuild tasks in the
Microsoft.Windows.SDK.BuildTools.MSIXpackage, so the SDK relies on supported Windows SDK tooling.Consumer Experience
Pipeline
BuildMsixorchestrator with a conditional pipeline:Default (CLI/CI): Publish -> Merge -> Validate -> CopyAssets -> ResourceIndex -> Pack -> Sign
VS dev-loop (layout mode): Publish -> Merge -> Validate -> CopyAssets -> ResourceIndex -> DeployLayout (skips Pack/Sign)
PublishToLayoutProjectReferencewithLayoutDirdotnet publishMergeAppxManifestMergeAppxFragmentstaskValidateAppxManifestValidateAppxManifesttaskCopyMsixAssetsMsixContentitemsCopyGenerateResourceIndexMakePri.exefor.resw(auto/true/false)WinAppSdkGetSdkFileFullPath+ MakePriPackMsix.msixWinAppSdkMakeAppxPackSignMsixWinAppSdkSignAppxPackagePlus opt-in targets:
CleanMsixLayout,InstallMsix,RegisterMsixLayout,UninstallMsixBuild tooling (Microsoft.Windows.SDK.BuildTools.MSIX)
The SDK uses the package's compiled tasks (namespace
Microsoft.Build.Msix):WinAppSdkGetSdkFileFullPath— locates MakeAppx / SignTool / MakePri in the installed Windows SDKWinAppSdkMakeAppxPack— packs the layout into the.msixfrom a generated[Files]mapping fileWinAppSdkSignAppxPackage— signs the.msix, with timestamp and Azure Code Signing / Key Vault supportIntegration (not bundled): the package is injected as a
PackageReferencefromSdk.propswithGeneratePathPropertyandExcludeAssets="build;buildTransitive", so only the task assembly is used and the package's heavyweight WinAppSDK pipeline is not imported. It is restored automatically (consumers do not add it manually).VersionOverrideis used under Central Package Management so no centralPackageVersionentry is required, and the task assembly is resolved per runtime (net6.0for Core,net472for desktop MSBuild). A smallRoslynCodeTaskFactoryinline task resolves the latest installed Windows SDK version forTargetPlatformVersion(honoringMsixWindowsSdkVersionwhen set).Key Features
MergeAppxFragments,ValidateAppxManifest; SDK-tool discovery, packing, and signing come from theMicrosoft.Windows.SDK.BuildTools.MSIXpackageMsixPackageVersion(4-part numeric)MsixContentitems for arbitrary content filesMsixSdkBuildToolsVersion,MsixWindowsSdkVersion,MsixHashAlgorithmId)What's Included
SDK Project (
src/MsixPackaging/)Microsoft.Build.MsixPackaging.csproj— netstandard2.0, follows Artifacts patternTasks/— 2 compiled MSBuild tasks (MergeAppxFragments,ValidateAppxManifest)Sdk/Sdk.props— NoTargets import, property defaults, build-tools package injection, VS property pageSdk/Sdk.targets— BuildMsix orchestrator + targets, using the build-tools package tasksSdk/Microsoft.Build.MsixPackaging.PropertyPage.xaml— VS Project Properties pagebuild/—.props/.targetsfor traditional NuGet package consumptionversion.json(1.0),README.mdUnit Tests (
src/MsixPackaging.UnitTests/)net472,net8.0,net9.0,net10.0MergeAppxFragmentsTests— version validation, fragment detection, attribute patching, indentationValidateAppxManifestTests— valid manifest, missing elements, duplicate IDs, malformed XML, invalid versionSample (
samples/MsixPackaging/)SampleConsoleApp/— trivial console app withAppxFragment.xmlandMsixImages/SamplePackaging.msbuildproj— consumes the SDK from the source tree (builds a real.msix)Package.base.appxmanifest— minimal manifest templateRepo Conventions
Microsoft.Build.MsixPackaging, task namespaceMicrosoft.Build.MsixPackaging.TasksMicrosoft.Windows.SDK.BuildTools.MSIXtasksglobal.jsonmsbuild-sdksFilesToSign(Authenticode + StrongName) for the task DLL1.0)BuildOutputTargetFolder=build\(Artifacts pattern)Testing
dotnet build --no-incremental— SDK compiles with 0 warnings, 0 errors (StyleCop clean)dotnet test— 14/14 tests pass across all 4 TFMs.msix(publish -> merge -> validate -> copy -> pack)