Skip to content

Add ability to specify Windows App SDK version in C# dotnet and VSIX templates#6523

Open
lauren-ciha wants to merge 20 commits into
mainfrom
user/laurenciha/default-highest-nuget-version-csharp-templates
Open

Add ability to specify Windows App SDK version in C# dotnet and VSIX templates#6523
lauren-ciha wants to merge 20 commits into
mainfrom
user/laurenciha/default-highest-nuget-version-csharp-templates

Conversation

@lauren-ciha

@lauren-ciha lauren-ciha commented May 29, 2026

Copy link
Copy Markdown
Member

Builds upon #6407 and resolves #6343

In previous PRs, the UseLatestWindowsAppSDK was used in the dotnet templates to update the template project dependencies to the latest version. However, if this option was unchecked or set to false, no dependencies would be installed at all. This PR fixes this error by setting the default dependency version to the latest version in the ProjectTemplate.csproj themselves with PackageReference and providing parameters to pass in specific NuGet package versions for each template's dependencies.

Before this PR, the VSIX templates installed their packages via the NuGetPackageInstaller wizard, even though C# projects have long had PackageReference support. The reason was to have one implementation to manage package installation for both C# and C++ templates. Now that the Windows App SDK templates extend beyond Visual Studio, it does not make sense for the C# templates to use the Wizard class when evergreen dependency versions can be written into the project files. Further work is needed to completely remove the wizard from the C# VSIX templates, however that is out of scope for this PR. Setting PackageReference... Version="*" simplifies the default NuGet dependency versioning for both dotnet and VSIX templates.

That only covers the default case. To accommodate custom versioning on template generation, I added {dependency}Version parameter for each of the template dependencies. When the parameter is empty, it is replaced with the latest version (*). Other templates have new parameters for their additional dependencies.

Walkthrough with the single-project/blank app template

To illustrate the changes, let's walk through the blank app/single-project packaged app template:

  • dev/Templates/Source/ProjectTemplates/Desktop/CSharp/SingleProjectPackagedApp/ProjectTemplate.csproj no longer has the dotnet conditional because we want VSIX dependencies to be resolved with PackageReference as well.
    *dev/Templates/Source/ProjectTemplates/Desktop/CSharp/SingleProjectPackagedApp/WinUI.Desktop.Cs.SingleProjectPackagedApp.vstemplate sets those CustomParameter to *. This makes sense for the VSIX templates since we do not have the UI to select versions (outside of the scope of this PR)
  • Then in dev/Templates/Dotnet/templates/blank-app/.template.config/template.json, UseLatestWindowsAppSDK has been removed and the default values for the other depdency versions have been replaced to the floating latest stable value (*). This will make the templates easier to maintain in the long run if we want the default value to be the highest stable available. Since the post-actions were updating to the latest version, they're no longer needed. If NuGet restore fails, there is a clear error to the user and since the dependencies have moved into the project file, we don't need to add another version on failure.
  • dev/Templates/Dotnet/templates/blank-app/.template.config/ide.host.json and dev/Templates/Dotnet/templates/blank-app/.template.config/dotnetcli.host.json surface these parameters to the user in Visual Studio and donet CLI respectively

These changes have been made to each of the C# templates.

Finally, dev/Templates/Dotnet/Test-DotnetNewTemplates.ps1 was updated to include tests for the version parameter parsing:

  • If a version parameter is left blank in the dotnet CLI, it's set to *
  • If a real Windows App SDK version is passed in, the instantiated project has that version
  • If multiple versions are pinned, those versions are set in the instantiated templates
  • If a prerelease string is included in the version (e.g. preview), the version is set correctly
  • If an invalid NuGet version was passed in, the parameter is passed to NuGet, but NuGet restore fails
  • If a valid NuGet version was passed in, but was not a WASDK version, the parameter is passed to NuGet, but NuGet restore fails

Considered paths (and the current limitations):

  • Command line/template level parameter validation would reduce the time it would take for someone to realize they made a typo. Unfortunately, parameter-level validation was not supported
  • Hiding the several version input boxes in VS' New Project menu behind a checkbox so that users would not have to look at all their versioning options if they just wanted the default. Unfortunately, although the boolean isVisible can be set, the values are set at instantiation time (e.g. VS' "Create" button) and are not responsive to user input. This is a Visual Studio limitation.

How I validated this PR:

  • Ran Test-DotnetNewTemplates.ps1 - passed
  • Manually installed, opened, and built all of the dotnet tests in VS - passed
  • Built and installed the vsix using build-install-localdev-vsix.ps1, then instantiated and built the templates in VS - passed
  • Verified that the VSIX from the aggregator pipeline (user/laurenciha/default-highest-nuget-version-csharp-templates) also builds and runs successfully
  • Manually verified the same test scenarios for the version parameters on the dotnet templates in the VS host and updated the tests to include the expected error codes

A microsoft employee must use /azp run to validate using the pipelines below.

WARNING:
Comments made by azure-pipelines bot maybe inaccurate.
Please see pipeline link to verify that the build is being ran.

For status checks on the main branch, please use TransportPackage-Foundation-PR
(https://microsoft.visualstudio.com/ProjectReunion/_build?definitionId=81063&_a=summary)
and run the build against your PR branch with the default parameters.

@lauren-ciha lauren-ciha force-pushed the user/laurenciha/default-highest-nuget-version-csharp-templates branch from dbefdc4 to 4aa8c5f Compare June 1, 2026 17:27
@lauren-ciha lauren-ciha requested review from DinahK-2SO, Scottj1s and guimafelipe and removed request for guimafelipe June 3, 2026 22:34
@lauren-ciha lauren-ciha force-pushed the user/laurenciha/default-highest-nuget-version-csharp-templates branch from 3286279 to 2229d21 Compare June 3, 2026 22:35
@lauren-ciha lauren-ciha marked this pull request as ready for review June 3, 2026 22:36
@lauren-ciha lauren-ciha requested review from MuyuanMS and niels9001 June 3, 2026 22:36

@DinahK-2SO DinahK-2SO left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @lauren-ciha , thanks for reaching out! I kicked off a test with our template validation pipeline (#6526) and found this new template will fail with dotnet8. Please try fixing it.

Repro steps:

dotnet new winui-mvvm -n MvvmRepro --dotnet-version net8.0 --force --no-update-check
cd MvvmRepro
dotnet build -p:Configuration=Debug -p:Platform=x64 -p:WindowsPackageType=None

Error:

Restore complete (1.0s)
MvvmRepro net8.0-windows10.0.26100.0 win-x64 failed with 6 error(s) and 1 warning(s) (9.5s)
C:\demo\templates_review\MvvmRepro\ViewModels\MainPageViewModel.cs(14,27): error CS8703: The modifier 'partial' is not valid for this item in C# 12.0. Please use language version '13.0' or greater.
C:\demo\templates_review\MvvmRepro\ViewModels\MainPageViewModel.cs(17,24): error CS8703: The modifier 'partial' is not valid for this item in C# 12.0. Please use language version '13.0' or greater.
C:\demo\templates_review\MvvmRepro\ViewModels\MainPageViewModel.cs(14,27): error CS9248: Partial property 'MainPageViewModel.Greeting' must have an implementation part.
C:\demo\templates_review\MvvmRepro\ViewModels\MainPageViewModel.cs(17,24): error CS9248: Partial property 'MainPageViewModel.Counter' must have an implementation part.
C:\demo\templates_review\MvvmRepro\ViewModels\MainPageViewModel.cs(14,27): error CS8050: Only auto-implemented properties, or properties that use the 'field' keyword, can have initializers.
C:.tools.nuget\packages\microsoft.windowsappsdk.winui\2.2.1\buildTransitive\Microsoft.UI.Xaml.Markup.Compiler.interop.targets(847,9): XamlCompiler warning WMC1509: No LocalAssembly parameter given during MarkupCompilePass2 for the currently building project. This will likely cause type resolution errors for any types from the current project.
C:.tools.nuget\packages\microsoft.windowsappsdk.winui\2.2.1\buildTransitive\Microsoft.UI.Xaml.Markup.Compiler.interop.targets(847,9): Xaml Internal Error error WMC9999: Object reference not set to an instance of an object.

Build failed with 6 error(s) and 1 warning(s) in 11.3s

@lauren-ciha lauren-ciha force-pushed the user/laurenciha/default-highest-nuget-version-csharp-templates branch from d4c7daa to 81e1e1d Compare June 12, 2026 16:51
@lauren-ciha

lauren-ciha commented Jun 12, 2026

Copy link
Copy Markdown
Member Author

Thank you for creating that validation pipeline and catching that error! The pipeline fails on the winui mvvm test with winui-mvvm_x64_4785f088\ViewModels\MainPageViewModel.cs(14,27): error CS8703: The modifier 'partial' is not valid for this item in C# 12.0. Please use language version 'preview' or greater. [C:\Users\ContainerAdministrator\AppData\Local\Temp\DotnetNewTemplateValidation\6dd416d5c0fd40a0af202a947ed7e7a6\winui-mvvm_x64_4785f088\winui-mvvm_x64_4785f088.csproj]

.NET 8.0 uses C# 12.0, while the partial modifier is supported in 12.0 preview and above. I had .NET 10 installed locally, so I didn't catch this on my local runs of Test-DotnetNewTemplates.ps1. I've made a PR that corrects the syntax from partial variables to fields in the MVVM template and adds a .NET version parameter to the test script so we can test against different .NET versions more easily.

To keep the git history clean, I've remove the winui-tabview and winui-mvvm tests from this branch. Let me know if you'd prefer to cherry pick those changes onto this branch instead of merging those into main directly.

lauren-ciha and others added 15 commits June 12, 2026 14:14
Replace hardcoded Version="*" PackageReferences with *$
template tokens in all 6 shared .csproj files. These tokens are
resolved by the dotnet new template engine (via template.json symbols)
and by the VSIX template engine (via CustomParameter entries).

Add defensive CustomParameter entries with Value="*" to each
.vstemplate file so that VSIX templates resolve the new tokens to
latest-version semantics, matching the dotnet new default behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the UseLatestWindowsAppSDK boolean and hardcoded version
defaults with freeform text parameters (defaultValue="*") that let
users pin specific NuGet package versions at scaffold time via
--wasdk-version, --build-tools-version, etc.

Remove all B17581D1 'update to latest' post-actions since floating
Version="*" already resolves to the latest stable release via NuGet.
The 210D431B restore post-action is retained.

Add version parameters to the class-library template which previously
had none.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the UseLatestWindowsAppSDK IDE entry with version parameter
entries so that IDEs like Visual Studio and Rider surface the new
version pinning options in their template dialogs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Register long and short CLI aliases for each version parameter:
  --wasdk-version / -wasdkv
  --build-tools-version / -btv
  --winapp-version / -wav
  --mvvm-toolkit-version / -mtv  (mvvm-app only)
  --mstest-version / -mv         (unit-test only)
  --test-sdk-version / -tsv      (unit-test only)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add winui-tabview and winui-mvvm to the template test matrix.

Add Assert-CsprojPackageVersion helper function and 6 test scenarios:
  1. Default (no version) produces Version="*"
  2. Single pinned version (--wasdk-version)
  3. All versions pinned
  4. Pre-release version string (e.g. 1.8.0-preview1)
  5. Invalid version: scaffold succeeds, build fails
  6. Nonexistent version (99.99.99): scaffold succeeds, build fails

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Dot-navigation on multiple ItemGroup elements fails when some lack
PackageReference children. Use SelectNodes XPath query instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add useLatestDependencies bool parameter (default: true) to all 6
template.json configs. In ide.host.json, version fields use
isVisible='!useLatestDependencies' so they only appear when the
checkbox is unchecked. CLI behavior is unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…to find package {packageName} wtih version {version})
@lauren-ciha lauren-ciha force-pushed the user/laurenciha/default-highest-nuget-version-csharp-templates branch from 5db3f6b to a59b023 Compare June 12, 2026 21:14
@lauren-ciha

Copy link
Copy Markdown
Member Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WinUI templates: unchecking UseLatestWindowsAppSDK omits Windows App SDK package references and breaks build

3 participants