From 70aaca685f413cbfb5b51355c1b7d72b37b51849 Mon Sep 17 00:00:00 2001 From: Dinah Xiaomgao G <116714259+DinahK-2SO@users.noreply.github.com> Date: Tue, 19 May 2026 14:01:28 +0800 Subject: [PATCH 01/10] init --- ...WinAppSdk.CSharp.DotnetNewTemplates.csproj | 10 +- .../Dotnet/templates/blank-app/Agents.md | 270 +++++++++++ .../accessibility.instructions.md | 62 +++ .../instructions/code-quality.instructions.md | 170 +++++++ .../design-principles.instructions.md | 134 ++++++ .../globalization.instructions.md | 55 +++ .../instructions/performance.instructions.md | 53 +++ .../instructions/security.instructions.md | 55 +++ .../instructions/testing.instructions.md | 284 ++++++++++++ .../instructions/windows-apis.instructions.md | 92 ++++ .../winui-best-practices.instructions.md | 420 ++++++++++++++++++ 11 files changed, 1604 insertions(+), 1 deletion(-) create mode 100644 dev/Templates/Dotnet/templates/blank-app/Agents.md create mode 100644 dev/Templates/Dotnet/templates/blank-app/instructions/accessibility.instructions.md create mode 100644 dev/Templates/Dotnet/templates/blank-app/instructions/code-quality.instructions.md create mode 100644 dev/Templates/Dotnet/templates/blank-app/instructions/design-principles.instructions.md create mode 100644 dev/Templates/Dotnet/templates/blank-app/instructions/globalization.instructions.md create mode 100644 dev/Templates/Dotnet/templates/blank-app/instructions/performance.instructions.md create mode 100644 dev/Templates/Dotnet/templates/blank-app/instructions/security.instructions.md create mode 100644 dev/Templates/Dotnet/templates/blank-app/instructions/testing.instructions.md create mode 100644 dev/Templates/Dotnet/templates/blank-app/instructions/windows-apis.instructions.md create mode 100644 dev/Templates/Dotnet/templates/blank-app/instructions/winui-best-practices.instructions.md diff --git a/dev/Templates/Dotnet/WinAppSdk.CSharp.DotnetNewTemplates.csproj b/dev/Templates/Dotnet/WinAppSdk.CSharp.DotnetNewTemplates.csproj index e432695bf7..7267d1eb81 100644 --- a/dev/Templates/Dotnet/WinAppSdk.CSharp.DotnetNewTemplates.csproj +++ b/dev/Templates/Dotnet/WinAppSdk.CSharp.DotnetNewTemplates.csproj @@ -146,7 +146,15 @@ foreach (var t in Templates) // 3. dotnet-new template configuration. EmitTree(Path.Combine(configDir, ".template.config"), contentRoot + "/.template.config"); - // 4. Shared .gitignore (one copy per template). + // 4. Optional companion assets (Agents.md, instructions/**). + string agentsPath = Path.Combine(configDir, "Agents.md"); + if (File.Exists(agentsPath)) + { + Emit(agentsPath, contentRoot + "/AGENTS.md"); + } + EmitTree(Path.Combine(configDir, "instructions"), contentRoot + "/.github/instructions"); + + // 5. Shared .gitignore (one copy per template). if (!string.IsNullOrEmpty(GitignoreSource) && File.Exists(GitignoreSource)) { Emit(GitignoreSource, contentRoot + "/gitignore.txt"); diff --git a/dev/Templates/Dotnet/templates/blank-app/Agents.md b/dev/Templates/Dotnet/templates/blank-app/Agents.md new file mode 100644 index 0000000000..d3da0bfa82 --- /dev/null +++ b/dev/Templates/Dotnet/templates/blank-app/Agents.md @@ -0,0 +1,270 @@ +# Copilot Agent Instructions -- WinUI 3 / WinAppSDK + +## Project Overview + +This is a **WinUI 3** desktop application built on the **Windows App SDK**. It uses MSIX packaging and supports x86, x64, and ARM64 architectures. + +> **Source of truth for versions & names:** Always read the project `.csproj` to determine the current `TargetFramework`, `RuntimeIdentifiers`, `Platforms`, `RootNamespace`, and `Microsoft.WindowsAppSDK` package version. Never hard-code project names or version numbers in instruction files. +> +> Throughout this document and the instruction files, `` is a placeholder -- replace it with the actual project folder/assembly name (derived from the `.csproj` filename). + +| Property | How to determine | +|---|---| +| UI Framework | WinUI 3 (`Microsoft.UI.Xaml`) -- always used | +| App SDK | Read `Microsoft.WindowsAppSDK` version from `.csproj` `` | +| Runtime / TFM | Read `` from `.csproj` (e.g., `net10.0-windows10.0.26100.0`) | +| Target OS | Derived from `` and `` in `.csproj` | +| Platforms | Read `` from `.csproj` (e.g., `x86;x64;ARM64`) | +| Packaging | MSIX (`true`) | +| Namespace | Read `` from `.csproj` | +| Nullable | Read `` from `.csproj` | + +> **Default TFM:** Templates ship with `net10.0` by default. Pass +> `--dotnet-version ` (for example `net10.0`) when running `dotnet new ...` +> or edit `` inside the generated `.csproj` before the first +> build if you need a newer framework. Keep `` synchronized +> with the framework you pick. + +## Instruction Files Index + +All detailed agent instructions are organized under `.github/instructions/`: + +| File | Scope | +|---|---| +| [design-principles.instructions.md](.github/instructions/design-principles.instructions.md) | DRY, KISS, SOLID, YAGNI | +| [globalization.instructions.md](.github/instructions/globalization.instructions.md) | Globalization & Localization | +| [accessibility.instructions.md](.github/instructions/accessibility.instructions.md) | Accessibility | +| [security.instructions.md](.github/instructions/security.instructions.md) | Security | +| [performance.instructions.md](.github/instructions/performance.instructions.md) | Performance | +| [code-quality.instructions.md](.github/instructions/code-quality.instructions.md) | Static Analysis, StyleCop, Code Cleanup | +| [winui-best-practices.instructions.md](.github/instructions/winui-best-practices.instructions.md) | WinUI 3 / WinAppSDK patterns & references | +| [windows-apis.instructions.md](.github/instructions/windows-apis.instructions.md) | WinAppSDK & Platform SDK API namespace catalog & lookup guidance | +| [testing.instructions.md](.github/instructions/testing.instructions.md) | Unit Testing, Build & Run | + +## Core Agent Workflow + +Every time you work on this codebase, follow this checklist: + +### Before Writing Code +1. **Review the original goal** -- Re-read the user's request and confirm you understand the intent. +2. **Check existing code** -- Search for related implementations to avoid duplication (DRY). +3. **Find the right API** -- If the task involves a platform capability (AI, UI controls, file access, notifications, windowing, widgets, sensors, etc.), first check the [Windows APIs catalog](.github/instructions/windows-apis.instructions.md) and then look up the correct API in the [WinUI 3 API Reference](https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/) before writing code. +4. **Plan the approach** -- Consider SOLID principles and identify which classes/interfaces are involved. + +### While Writing Code + +> **Agent Rule -- MANDATORY:** Steps 5-8 are **not** passive references. You **must** actually open and read the linked instruction file before writing code that falls within its scope. Do not skip this -- these files contain rules, anti-patterns, and checklists that must be applied. + +5. **Apply Design Principles** -- **Read** [design-principles](.github/instructions/design-principles.instructions.md) before adding/refactoring classes or logic. Apply DRY, KISS, SOLID, YAGNI. +6. **Follow Fundamentals** -- **Read the applicable instruction files** based on what you're changing: + - Adding or changing **UI controls / XAML**? -> Read [accessibility](.github/instructions/accessibility.instructions.md) (AutomationProperties, keyboard nav, contrast) AND [performance](.github/instructions/performance.instructions.md) (x:Bind, x:Load, virtualization). + - Adding or changing **user-facing strings** (labels, messages, tooltips)? -> Read [globalization](.github/instructions/globalization.instructions.md) (`.resw` files, `x:Uid`, `ResourceLoader`). + - Handling **secrets, user input, HTTP, or permissions**? -> Read [security](.github/instructions/security.instructions.md) (no hard-coded secrets, input validation, least privilege). + - Working on **data binding, collections, async/IO, or layout**? -> Read [performance](.github/instructions/performance.instructions.md) (x:Bind, virtualization, async patterns). +7. **Respect Code Quality Rules** -- **Read** [code-quality](.github/instructions/code-quality.instructions.md) before writing code. Follow all CA*/SA*/IDE* analyzer rules and naming conventions. +8. **Follow WinUI Patterns** -- **Read** [winui-best-practices](.github/instructions/winui-best-practices.instructions.md) for MVVM, x:Bind, community toolkit, and API verification. + +### After Writing Code +9. **Remove unused code** -- Delete unused `using` statements, dead code, commented-out blocks. +10. **Write unit tests** -- Every new public method/class needs tests. **Read** [testing](.github/instructions/testing.instructions.md) for framework setup, naming conventions (`MethodName_Scenario_ExpectedResult`), AAA pattern, and `dotnet test` commands. +11. **Build the project** -- Detect the platform first (`$Platform = $env:PROCESSOR_ARCHITECTURE`), then run `dotnet build -c Debug -p:Platform=$Platform` from the project folder and fix all warnings/errors. **If build errors occur, follow the Troubleshooting Build Errors workflow below.** +12. **Run tests** -- Run tests related to the change using `--filter` (see [testing](.github/instructions/testing.instructions.md)). Run the full suite only when the change is cross-cutting. +13. **Run the app with package identity** -- Use `dotnet run` (preferred -- the project references `Microsoft.Windows.SDK.BuildTools.WinApp`, which automatically invokes `winapp run` to register a loose-layout package and launch via AUMID). See [Build, Run & Deploy](#build-run--deploy) below for advanced scenarios. +14. **Re-review against original goal** -- Confirm the implementation matches the user's request. + +### Troubleshooting Build Errors + +> **Agent Rule -- MANDATORY:** When a build fails due to an unknown type, missing namespace, unresolved API, or similar definition error, follow this escalation order. **Do NOT jump straight to reading `.winmd` files or using `ildasm`/decompilers** -- always try web search first. + +**Step 1 -- Web Search (ALWAYS try first):** +1. Open and read [windows-apis.instructions.md](.github/instructions/windows-apis.instructions.md) -- it contains the API namespace catalog and lookup guidance. +2. Translate the unknown type/namespace into search keywords (e.g., `ImageDescription` -> "WinAppSDK ImageDescription API"). +3. Use `web_search` or `web_fetch` to search the [WinAppSDK API Reference](https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/) and the [Platform SDK API Reference](https://learn.microsoft.com/en-us/uwp/api/) for the correct namespace, class name, and method signatures. +4. Check the [release notes](https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/stable-channel) to verify the API is available in the project's SDK version (read from `.csproj`). + +**Step 2 -- Sample Repos:** +If web search finds the API but usage is unclear, search the sample repositories listed in [windows-apis.instructions.md](.github/instructions/windows-apis.instructions.md) for working examples. + +**Step 3 -- WinMD / Decompiler (last resort only):** +Only if Steps 1-2 fail to resolve the issue, then inspect `.winmd` metadata files or use decompilation tools to discover the exact type definitions. This is a fallback, not the default approach. + +## Build, Run & Deploy + +This is an MSIX-packaged WinUI 3 app. You **must** pass both `-c` (Configuration) and `-p:Platform=` to every `dotnet build`/`dotnet test` command. + +This template references the [`Microsoft.Windows.SDK.BuildTools.WinApp`](https://www.nuget.org/packages/Microsoft.Windows.SDK.BuildTools.WinApp) NuGet package, which hooks `dotnet run` to invoke the [`winapp` CLI](https://github.com/microsoft/WinAppCli). Use `dotnet run` for everyday inner-loop development -- you do not need to call `Add-AppxPackage` or `MakeAppx.exe` by hand. + +### Dotnet CLI Workflow + +- Prefer `dotnet new` for scaffolding projects and items so namespaces, GUIDs, + and resource wiring stay correct. +- Common commands: + - `dotnet new winui -n MyApp` + - `dotnet new winui-page -n SettingsPage --project .\MyApp\MyApp.csproj` + - `dotnet new winui-usercontrol -n ProfileCard --project .\MyApp\MyApp.csproj` +- Discover available scaffolds with `dotnet new winui --list` (shows supported + parameters such as `--dotnet-version`). +- Need a newer TFM? Supply `--dotnet-version net10.0` during scaffold or edit + `` afterward before the first build. + +### Prerequisites + +- **Developer Mode must be enabled** on Windows. Verify with: + ```powershell + # Check developer mode + Get-WindowsDeveloperLicense + # If not enabled: Settings -> System -> For developers -> Developer Mode -> On + ``` +- **`winapp` CLI** -- installed transitively via the `Microsoft.Windows.SDK.BuildTools.WinApp` NuGet reference (no separate install needed for `dotnet run`). To use `winapp` directly from the terminal for advanced scenarios (manifest editing, certificate management, packaging), install it standalone: + ```powershell + winget install Microsoft.WinAppCli --source winget + ``` + +### Detect Platform + +**Always detect the machine's architecture first** -- never hardcode a platform value. Run this once at the start of every build/test session: + +```powershell +# Detect the current machine's CPU architecture +# (returns AMD64 on x64 boxes, ARM64 on ARM64 boxes, x86 on 32-bit boxes) +$arch = $env:PROCESSOR_ARCHITECTURE +$Platform = if ($arch -eq 'AMD64') { 'x64' } else { $arch } # MSBuild expects x64/x86/ARM64 +``` + +Use `$Platform` in all subsequent `dotnet` commands. + +### Build + +```powershell +# Run from the project folder containing the .csproj +cd + +# Detect platform (see above) +$arch = $env:PROCESSOR_ARCHITECTURE +$Platform = if ($arch -eq 'AMD64') { 'x64' } else { $arch } + +# Debug build (matches current machine) +dotnet build -c Debug -p:Platform=$Platform + +# Release build +dotnet build -c Release -p:Platform=$Platform +``` + +### Run with Package Identity (preferred) + +The template references `Microsoft.Windows.SDK.BuildTools.WinApp`, which makes `dotnet run` register a loose-layout package via `winapp run` and launch the app via AUMID activation -- giving it the same package identity it would have in production: + +```powershell +$arch = $env:PROCESSOR_ARCHITECTURE +$Platform = if ($arch -eq 'AMD64') { 'x64' } else { $arch } + +dotnet run -c Debug -p:Platform=$Platform +``` + +The CLI prints the registered package's AUMID and the launched process's PID -- attach a debugger to that PID for runtime debugging. + +#### Useful MSBuild knobs (set in `.csproj` ``) + +| Property | When to set | +|---|---| +| `EnableWinAppRunSupport=false` | Disable the `dotnet run` integration entirely (e.g., to launch unpackaged) | +| `WinAppRunUseExecutionAlias=true` | For console apps -- launches via `uap5:ExecutionAlias` so stdin/stdout stay in the terminal. Add the alias first with `winapp manifest add-alias`. | +| `WinAppRunNoLaunch=true` | Register the package but don't launch (attach your IDE's debugger before launch) | +| `WinAppLaunchArgs="--flag value"` | Pass arguments to the app on launch | + +#### Manual `winapp run` (when not using `dotnet run`) + +```powershell +# Read from .csproj first; example uses net10.0-windows10.0.26100.0 +winapp run .\bin\$Platform\Debug\ + +# Pass args after -- to avoid escaping +winapp run .\bin\$Platform\Debug\ -- --my-flag value + +# Console app: keep stdin/stdout in the current terminal (requires uap5:ExecutionAlias) +winapp run .\bin\$Platform\Debug\ --with-alias + +# Wipe LocalState/settings between runs to test first-run behavior +winapp run .\bin\$Platform\Debug\ --clean +``` + +#### Run Tests + +```powershell +# Run from the test project folder +cd .Tests +$arch = $env:PROCESSOR_ARCHITECTURE +$Platform = if ($arch -eq 'AMD64') { 'x64' } else { $arch } +dotnet test -c Debug -p:Platform=$Platform +``` + +### winapp CLI command reference + +The `winapp` CLI is the canonical entry point for app-identity, packaging, certificate, and asset operations. Reach for it instead of hand-rolling `MakeAppx`/`SignTool`/`Add-AppxPackage` invocations. + +| Scenario | Command | Notes | +|---|---|---| +| **Run/debug with identity (loose layout)** | `dotnet run` (or `winapp run `) | Default for inner loop. Registers full loose-layout package. | +| **Console app inner loop** | Set `WinAppRunUseExecutionAlias=true` in `.csproj`, then `dotnet run` | Requires `uap5:ExecutionAlias` -- add via `winapp manifest add-alias`. | +| **Sparse identity on a single exe** | `winapp create-debug-identity .\bin\Debug\\.exe` | Use when the exe is outside the build folder, or for IDE F5 startup debugging. | +| **Stop debugging / clean up** | `winapp unregister` | Removes dev packages registered for the current project. | +| **Generate dev signing cert** | `winapp cert generate --manifest .\Package.appxmanifest --install` | Reads publisher from manifest. Stored as `devcert.pfx` in the project. | +| **Inspect a cert** | `winapp cert info .\devcert.pfx` | Verify subject matches manifest publisher. | +| **Sign a file** | `winapp sign .\MyApp.msix --cert .\devcert.pfx` | Wraps `signtool`. | +| **Build distribution MSIX** | `winapp pack .\bin\$Platform\Release\\win- --cert .\devcert.pfx` | Auto-resolves `$targetnametoken$`, registers third-party WinRT components. | +| **Self-contained MSIX (bundles WinAppSDK)** | `winapp pack ... --self-contained` | No runtime dependency on the framework package. | +| **Regenerate Square44/Square150/etc. icons** | `winapp manifest update-assets .\branding\logo.svg` | SVG preferred -- rendered at all 5 scale and 14 targetsize variants. | +| **Add execution alias** | `winapp manifest add-alias` | Required for console-app inline I/O via `WinAppRunUseExecutionAlias`. | +| **Underlying SDK tools** | `winapp tool signtool ...`, `winapp tool makeappx ...` | Falls back to the raw [`Microsoft.Windows.SDK.BuildTools`](https://www.nuget.org/packages/Microsoft.Windows.SDK.BuildTools/) tools when needed. | + +For full reference, see the [winapp CLI usage docs](https://github.com/microsoft/WinAppCli/blob/main/docs/usage.md) and the [Debugging Guide](https://github.com/microsoft/WinAppCli/blob/main/docs/debugging.md). + +### Fallback: register a loose layout manually + +Only use this if you've explicitly disabled the `winapp` integration (`false`) or are debugging the deployment itself. The supported path is `dotnet run` / `winapp run`. + +```powershell +$arch = $env:PROCESSOR_ARCHITECTURE +$Platform = if ($arch -eq 'AMD64') { 'x64' } else { $arch } +$Rid = $Platform.ToLower() # arm64, x64, x86 + +# Register the built MSIX package from the build output +# Read from .csproj to build the correct path. +Add-AppxPackage -Register ".\\bin\$Platform\Debug\\win-$Rid\AppxManifest.xml" +``` + +> **Note:** Replace `` with the actual value from `.csproj` (e.g., `net10.0-windows10.0.26100.0`). + +If the launch fails because an old instance is still running, terminate it with `taskkill /IM .exe /F` before re-running. + +## Key Rules (Always Enforced) + +- **Every change must build and pass tests** -- Run `dotnet build` and `dotnet test` (see [Build, Run & Deploy](#build-run--deploy)) before considering any task complete. +- **Follow all instruction files** -- The detailed rules in `.github/instructions/` are authoritative. **You must actually open and read them** (not just acknowledge they exist) when working within their scope. See the trigger conditions in steps 5-8 above. +- **Web search before decompilation** -- When facing unknown types or build errors, always search the web / API docs first. Only use WinMD/ILDASM as a last resort (see [Troubleshooting Build Errors](#troubleshooting-build-errors)). +- **Use `winapp` for app-identity / packaging / signing** -- Don't hand-roll `MakeAppx`/`SignTool`/`Add-AppxPackage` invocations. The CLI keeps the manifest, certificate, and registration steps in sync. + +## Windows AI Prerequisites + +When integrating Windows AI APIs (Phi Silica, Windows Vision -- ImageDescription, +TextRecognizer, ImageScaler, etc.) -- see +[windows-apis.instructions.md](.github/instructions/windows-apis.instructions.md): + +1. **Package identity is required.** All Windows AI APIs require the app to + run with package identity. The `dotnet run` flow described above already + provides this. If you're testing outside `dotnet run`, register identity + first with `winapp run` or `winapp create-debug-identity`. +2. **Manifest capabilities.** Add the capabilities each API requires to + `Package.appxmanifest` (commonly `runFullTrust`; some scenarios additionally + need `internetClient`). Check the API's docs page for the exact list. +3. **Hardware / OS gating.** Some APIs require a Copilot+ PC (NPU) or a + minimum Windows build. Always probe availability with the API's + `IsAvailable` / `EnsureReadyAsync` pattern (or equivalent) and provide a + graceful fallback for unsupported devices. +4. **Verify locally before checking in.** After capability or manifest + changes, re-run `dotnet run` (or `winapp run`) so the registered identity + reflects the updated manifest -- a stale registration will silently use + the old capability set. + + + diff --git a/dev/Templates/Dotnet/templates/blank-app/instructions/accessibility.instructions.md b/dev/Templates/Dotnet/templates/blank-app/instructions/accessibility.instructions.md new file mode 100644 index 0000000000..e54c035577 --- /dev/null +++ b/dev/Templates/Dotnet/templates/blank-app/instructions/accessibility.instructions.md @@ -0,0 +1,62 @@ +--- +description: 'Accessibility requirements for interactive controls, keyboard navigation, screen readers, and contrast' +applyTo: '**/*.cs, **/*.xaml' +--- + +# Accessibility + +These rules apply to **every UI change**. They are not optional add-ons. + +--- + +## Rules + +- **Every interactive control** must have an `AutomationProperties.Name` or `AutomationProperties.LabeledBy`. +- Add a stable, unique `AutomationProperties.AutomationId` for controls targeted by UI automation tests (and for key interactive elements). +- Use semantic XAML controls — prefer `Button`, `HyperlinkButton`, `ListView` over styled `Border`/`Grid` with click handlers. +- Ensure **keyboard navigation** works for all features: + - Logical tab order via `TabIndex`. + - `AccessKey` bindings for frequently used actions. + - `KeyboardAccelerator` for shortcut keys. +- Maintain **minimum contrast ratios** (4.5:1 for normal text, 3:1 for large text) — test in High Contrast mode. +- Support **screen readers** (Narrator / NVDA): test that all content is announced correctly. +- Images must have `AutomationProperties.Name` describing the image purpose (or `AutomationProperties.AccessibilityView="Raw"` for decorative images). +- Do not rely on colour alone to convey meaning — add icons, text, or patterns. + +## Anti-patterns + +- Clickable `TextBlock` or `Image` without `AutomationProperties`. +- Custom controls that are not keyboard-focusable. +- Using `Visibility.Collapsed` to "hide" content from screen readers (use `AccessibilityView` instead). + +## Validation + +- Build & register the MSIX package — see **Build, Run & Deploy** in `.github/agents/Agents.md`. +- Test keyboard navigation: tab through every new/changed UI area. +- Test High Contrast: switch to Windows High Contrast theme and verify readability. +- Run Accessibility Insights for Windows on the app. + +### Verification Checklist + +- [ ] All interactive controls have `AutomationProperties.Name` +- [ ] Keyboard navigation works for the changed area +- [ ] Tested with High Contrast theme enabled +- [ ] Tab through the entire UI with keyboard only. +- [ ] Verify key interactive controls have stable, unique `AutomationProperties.AutomationId` values (especially controls used by UI automation tests). +- [ ] Switch to Windows High Contrast theme and verify readability. +- [ ] Run Narrator and verify all controls are announced correctly. +- [ ] Run **Accessibility Insights for Windows** on the app. + +## Must Read & Research + +> **Agent Rule:** Before any accessibility-related change, you **must** fetch and review these references using `fetch_webpage`. Apply what you learn. + +| # | Reference | When to consult | +|---|---|---| +| 1 | [Accessibility in WinUI](https://learn.microsoft.com/en-us/windows/apps/design/accessibility/accessibility) | Any UI change — verify accessibility approach | +| 2 | [AutomationProperties](https://learn.microsoft.com/en-us/windows/apps/design/accessibility/basic-accessibility-information) | Adding or modifying interactive controls | +| 3 | [Accessibility Insights](https://accessibilityinsights.io/docs/windows/overview/) | Testing tool — run before finalizing UI changes | +| 4 | [Keyboard Accessibility](https://learn.microsoft.com/en-us/windows/apps/design/accessibility/keyboard-accessibility) | Adding navigation, focus management, or shortcut keys | +| 5 | [High Contrast Themes](https://learn.microsoft.com/en-us/windows/apps/design/accessibility/high-contrast-themes) | Adding custom styles, colours, or theme resources | + + diff --git a/dev/Templates/Dotnet/templates/blank-app/instructions/code-quality.instructions.md b/dev/Templates/Dotnet/templates/blank-app/instructions/code-quality.instructions.md new file mode 100644 index 0000000000..d18b4b8983 --- /dev/null +++ b/dev/Templates/Dotnet/templates/blank-app/instructions/code-quality.instructions.md @@ -0,0 +1,170 @@ +--- +description: 'Static analysis, StyleCop, EditorConfig, naming conventions, and code cleanup rules' +applyTo: '**/*.cs, **/*.editorconfig, **/stylecop.json' +--- + +# Code Quality — Static Analysis, StyleCop & Code Cleanup + +Maintain strict code quality through automated analysis and consistent style enforcement. + +--- + +## 1. Static Analysis (Roslyn Analyzers) + +### Required Analyzer Packages + +Add these to the `.csproj` if not already present: + +```xml + + + + + all + runtime; build; native; contentfiles; analyzers + + +``` + +### Analysis Configuration in `.csproj` + +```xml + + true + latest-recommended + true + false + enable + +``` + +### Rule Enforcement + +Follow **all** CA* (quality) and IDE* (code style) analyzer rules at their configured severity. Do not cherry-pick — obey every warning the analyzers report. When encountering a specific rule violation, fetch the corresponding documentation from the **Must Read & Research** references below to understand and apply the correct fix. + +### `.editorconfig` + +The project's `.editorconfig` in the solution root is the source of truth for code style. Obey all rules defined there. When creating or modifying `.editorconfig`, fetch the [EditorConfig Reference](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/code-style-rule-options) for the full list of available settings. + +Key project conventions enforced via `.editorconfig`: +- Private fields use `_camelCase` prefix (SA1101 suppressed, SA1309 suppressed). +- File-scoped namespaces are required. +- `this.` qualification is not used. + +--- + +## 2. StyleCop Rules + +### StyleCop Configuration (`stylecop.json`) + +Place this file in the project root alongside the `.csproj`: + +```json +{ + "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "documentationRules": { + "companyName": "YourProjectName", + "copyrightText": "Copyright (c) {companyName}. All rights reserved.", + "xmlHeader": false, + "documentInterfaces": true, + "documentExposedElements": true, + "documentInternalElements": false, + "documentPrivateElements": false, + "documentPrivateFields": false + }, + "orderingRules": { + "usingDirectivesPlacement": "outsideNamespace", + "systemUsingDirectivesFirst": true + }, + "layoutRules": { + "newlineAtEndOfFile": "require" + }, + "namingRules": { + "allowCommonHungarianPrefixes": false + } + } +} +``` + +### Rule Enforcement + +Follow **all** SA* (StyleCop) rules at their configured severity. When encountering a specific SA* violation, fetch the [StyleCop Rules Reference](https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/DOCUMENTATION.md) to understand the rule and apply the correct fix. Do not suppress rules without justification in a code comment. + +--- + +## 3. Code Cleanup Rules (Always Enforced) + +### After Every Edit + +1. **Remove unused `using` statements** — No unused imports should remain. +2. **Remove commented-out code** — Version control tracks history; dead code is noise. +3. **Remove unused variables and fields** — If it's declared but never read, delete it. +4. **Remove empty methods** — If an event handler or override does nothing, remove it. +5. **Simplify code** — Apply IDE suggestions (IDE0001–IDE0090) for: + - Removing unnecessary casts + - Simplifying `default` expressions + - Using pattern matching + - Using null-coalescing operators + +### Naming Conventions + +| Element | Convention | Example | +|---|---|---| +| Class / Struct | PascalCase | `MainViewModel` | +| Interface | I + PascalCase | `INavigationService` | +| Public method | PascalCase | `LoadDataAsync()` | +| Private method | PascalCase | `ValidateInput()` | +| Public property | PascalCase | `CurrentPage` | +| Private field | _camelCase | `_settingsService` | +| Parameter | camelCase | `userName` | +| Local variable | camelCase | `itemCount` | +| Constant | PascalCase | `MaxRetryCount` | +| Async method | Suffix `Async` | `FetchDataAsync()` | +| Boolean | Prefix `Is/Has/Can` | `IsLoading`, `HasAccess` | + +### File Organization + +Each `.cs` file should follow this order: + +1. `using` directives (System first, then others, alphabetically) +2. Namespace declaration (file-scoped) +3. Class/struct/interface declaration +4. Inside the type: + 1. Constants + 2. Static fields + 3. Instance fields + 4. Constructors + 5. Properties + 6. Public methods + 7. Private/internal methods + 8. Event handlers + 9. Nested types + +--- + +## Validation + +- Build & register the MSIX package — see **Build, Run & Deploy** in `.github/agents/Agents.md`. +- Fix **all** warnings — do not suppress without justification in a code comment. +- Verify no unused `using` statements remain after every edit. +- Verify no commented-out code remains. +- Confirm naming conventions match the table above for every new symbol. + +--- + +## Must Read & Research + +> **Agent Rule:** Before configuring analyzers, fixing warnings, or adjusting code style, you **must** fetch and review the relevant references below using `fetch_webpage`. Apply what you learn — do not skip this step. + +| # | Reference | When to consult | +|---|---|---| +| 1 | [.NET Code Analysis Overview](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/overview) | Setting up or modifying analyzer configuration | +| 2 | [Code Style Rules (IDE0001–IDE0090)](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/) | Resolving IDE* warnings or adjusting `.editorconfig` | +| 3 | [Quality Rules (CA*)](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/) | Resolving CA* warnings or suppressing with justification | +| 4 | [StyleCop.Analyzers GitHub](https://github.com/DotNetAnalyzers/StyleCopAnalyzers) | Adding/updating StyleCop package or configuration | +| 5 | [StyleCop Rules Reference](https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/DOCUMENTATION.md) | Understanding specific SA* rule violations | +| 6 | [EditorConfig Reference](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/code-style-rule-options) | Modifying `.editorconfig` style or severity settings | +| 7 | [.NET Naming Conventions](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/identifier-names) | Verifying naming patterns for types, members, parameters | + + diff --git a/dev/Templates/Dotnet/templates/blank-app/instructions/design-principles.instructions.md b/dev/Templates/Dotnet/templates/blank-app/instructions/design-principles.instructions.md new file mode 100644 index 0000000000..296f716464 --- /dev/null +++ b/dev/Templates/Dotnet/templates/blank-app/instructions/design-principles.instructions.md @@ -0,0 +1,134 @@ +--- +description: 'Design principles (DRY, KISS, SOLID, YAGNI) enforced in every code change' +applyTo: '**/*.cs, **/*.xaml' +--- + +# Design Principles + +Apply these principles in **every change** you make to this codebase. When in doubt, favour simplicity and clarity over cleverness. + +--- + +## 1. DRY — Don't Repeat Yourself + +> *"Every piece of knowledge must have a single, unambiguous, authoritative representation within a system."* + +### Rules +- Before writing new code, **search** the codebase for existing implementations that solve the same problem. +- Extract shared logic into helper methods, base classes, or services. +- If you find duplicated code during a task, **refactor it** as part of the same change. +- Prefer generic/reusable components over copy-paste variations. + +### Anti-patterns to avoid +- Copy-pasting code between classes/files instead of extracting a shared method. +- Creating multiple converters/helpers that do the same thing. +- Duplicating validation logic across ViewModel and Model layers. + +--- + +## 2. KISS — Keep It Simple, Stupid + +> *"Simplicity is the ultimate sophistication."* + +### Rules +- Choose the **simplest approach** that meets the requirement. +- Avoid unnecessary abstractions, inheritance hierarchies, or patterns that add complexity without clear benefit. +- Write code that **reads like plain English** — favour descriptive names over comments. +- If a method is longer than ~30 lines, consider splitting it. +- If a class does more than one thing, split it (see SRP below). + +### Anti-patterns to avoid +- Over-engineering with factories/builders/strategies for simple object creation. +- Creating deep inheritance trees when composition would suffice. +- Using complex LINQ chains when a simple `foreach` is clearer. + +--- + +## 3. SOLID Principles + +### 3.1 SRP — Single Responsibility Principle +> *"A class should have only one reason to change."* + +- Each class/file should have **one clear responsibility**. +- ViewModels handle UI state & commands. Services handle business logic. Models hold data. +- If a class name contains "And" or "Manager", it likely violates SRP. + +### 3.2 OCP — Open/Closed Principle +> *"Software entities should be open for extension, but closed for modification."* + +- Use interfaces and abstract classes so behaviour can be extended without modifying existing code. +- Prefer adding new implementations over modifying existing ones. +- Use dependency injection to swap implementations. + +### 3.3 LSP — Liskov Substitution Principle +> *"Objects of a superclass should be replaceable with objects of its subclasses without altering correctness."* + +- Derived classes must honour the contracts of their base classes. +- Never throw `NotImplementedException` in overridden methods — if a subclass can't fulfil the contract, the inheritance is wrong. + +### 3.4 ISP — Interface Segregation Principle +> *"No client should be forced to depend on methods it does not use."* + +- Keep interfaces small and focused. +- Prefer multiple small interfaces over one large one. +- Example: `INavigationService`, `IDialogService`, `ISettingsService` — not `IAppService`. + +### 3.5 DIP — Dependency Inversion Principle +> *"Depend upon abstractions, not concretions."* + +- High-level modules must not depend on low-level modules. Both should depend on abstractions. +- Use constructor injection for dependencies. +- Register services in a DI container (e.g., `Microsoft.Extensions.DependencyInjection`). + +--- + +## 4. YAGNI — You Aren't Gonna Need It + +> *"Don't add functionality until it is necessary."* + +### Rules +- Only implement what is **explicitly requested** or **clearly needed right now**. +- Do not add "just in case" parameters, methods, or abstractions. +- If you're unsure whether something is needed, **leave it out** — it can always be added later. + +### Anti-patterns to avoid +- Adding unused interface methods "for future use". +- Building a generic framework when a single concrete class suffices. +- Creating configuration options nobody has asked for. + +--- + +## Quick Reference Checklist + +Before submitting any code change, verify: + +- [ ] No duplicated code exists (DRY) +- [ ] The solution is as simple as possible (KISS) +- [ ] Each class has one responsibility (SRP) +- [ ] New behaviour is added via extension, not modification (OCP) +- [ ] Derived types can substitute their base types (LSP) +- [ ] Interfaces are small and focused (ISP) +- [ ] Dependencies point toward abstractions (DIP) +- [ ] No speculative features were added (YAGNI) + +## Validation + +- Review every new/changed class for SRP violations — ask "does this class have more than one reason to change?" +- Search the codebase for duplicate logic before adding new helpers: `grep_search` for similar method names or patterns. +- Verify no speculative code was added — every line must trace back to the original request. +- Build & register the MSIX package — see **Build, Run & Deploy** in `.github/agents/Agents.md`. + +--- + +## Must Read & Research + +> **Agent Rule:** Before making any code change related to design principles, you **must** fetch and review the relevant references below using `fetch_webpage`. Apply what you learn — do not skip this step. + +| # | Reference | When to consult | +|---|---|---| +| 1 | [SOLID Principles in C# — Microsoft Learn](https://learn.microsoft.com/en-us/archive/msdn-magazine/2014/may/csharp-best-practices-dangers-of-violating-solid-principles-in-csharp) | Adding/refactoring classes, interfaces, or inheritance | +| 2 | [.NET Design Guidelines](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/) | Designing public APIs, naming, type design | +| 3 | [Framework Design Guidelines (Book)](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/) | Deep-dive on member design, exception patterns, collections | +| 4 | [Clean Code Summary](https://gist.github.com/wojteklu/73c6914cc446146b8b533c0988cf8d29) | Code readability, function size, naming clarity | + + diff --git a/dev/Templates/Dotnet/templates/blank-app/instructions/globalization.instructions.md b/dev/Templates/Dotnet/templates/blank-app/instructions/globalization.instructions.md new file mode 100644 index 0000000000..6816b6df50 --- /dev/null +++ b/dev/Templates/Dotnet/templates/blank-app/instructions/globalization.instructions.md @@ -0,0 +1,55 @@ +--- +description: 'Globalization & Localization requirements for user-facing strings, resource files, and culture-aware formatting' +applyTo: '**/*.cs, **/*.xaml, **/*.resw' +--- + +# Globalization & Localization + +These rules apply to **every feature and change** involving user-facing text. They are not optional add-ons. + +--- + +## Rules + +- **All user-facing strings** (UI text, error messages, tooltips) must come from `.resw` resource files — never hard-code them in XAML or C#. +- Resource file location: `Strings/en-us/Resources.resw` (default locale). +- Use `x:Uid` in XAML to bind controls to resource keys: + ```xml + + ``` + With a matching `.resw` entry: `WelcomeMessage.Text` = "Welcome!" +- In code-behind / ViewModels, use the `ResourceLoader`: + ```csharp + var loader = new Microsoft.Windows.ApplicationModel.Resources.ResourceLoader(); + string message = loader.GetString("ErrorFileNotFound"); + ``` +- **Format dates, numbers, and currencies** using `CultureInfo.CurrentCulture` or `DateTimeFormatter` — never assume a specific regional format. +- Avoid concatenating translated strings — use format placeholders (`{0}`, `{1}`). +- Design UI layouts to accommodate text expansion (~30-40% longer for German vs. English). + +## Anti-patterns + +- Hard-coded strings in `.xaml` or `.cs` files (e.g., `Content="Save"`). +- Using `string.Format` with hard-coded ordinal assumptions. +- Fixed-width UI elements that clip translated text. + +## Validation + +- Build & register the MSIX package — see **Build, Run & Deploy** in `.github/agents/Agents.md`. +- Check for hard-coded strings: search `Content="` and `Text="` in `.xaml` files — replace with `x:Uid`. + +### Verification Checklist + +- [ ] All user-facing strings are in `.resw` resource files + +## Must Read & Research + +> **Agent Rule:** Before any localization-related change, you **must** fetch and review these references using `fetch_webpage`. Apply what you learn. + +| # | Reference | When to consult | +|---|---|---| +| 1 | [Globalize your WinUI app](https://learn.microsoft.com/en-us/windows/apps/design/globalizing/guidelines-and-checklist-for-globalizing-your-app) | Adding any new user-facing strings or culture-aware formatting | +| 2 | [Resource Management System](https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/mrtcore/localize-strings) | Setting up or modifying `.resw` files and `ResourceLoader` usage | +| 3 | [WinUI Localization with x:Uid](https://learn.microsoft.com/en-us/windows/apps/develop/ui-input/localizing-strings) | Binding XAML controls to localized resources via `x:Uid` | + + diff --git a/dev/Templates/Dotnet/templates/blank-app/instructions/performance.instructions.md b/dev/Templates/Dotnet/templates/blank-app/instructions/performance.instructions.md new file mode 100644 index 0000000000..09eed79a92 --- /dev/null +++ b/dev/Templates/Dotnet/templates/blank-app/instructions/performance.instructions.md @@ -0,0 +1,53 @@ +--- +description: 'Performance requirements for data binding, layout, threading, and collection virtualization' +applyTo: '**/*.cs, **/*.xaml' +--- + +# Performance + +These rules apply to **every feature and change**. They are not optional add-ons. + +--- + +## Rules + +- **Use `x:Bind`** (compiled bindings) instead of `{Binding}` — it's faster and type-safe. +- Use **`x:Load`** (or `x:DeferLoadStrategy`) to defer loading of UI elements not immediately visible. +- Avoid heavy work on the UI thread — use `Task.Run` for CPU-bound work and `async/await` for I/O. +- Use **virtualizing panels** (`ItemsRepeater` with `StackLayout`, or `ListView`) for long lists — never use `StackPanel` with hundreds of items. +- **Cache** expensive computations and HTTP responses when appropriate. +- Minimize XAML visual tree depth — deep nesting hurts layout performance. +- Use **incremental loading** (`ISupportIncrementalLoading`) for large data sets. +- Profile with **Visual Studio Diagnostics Tools** and **PerfView** before and after optimizations. +- Be cautious with `DispatcherQueue.TryEnqueue` — don't flood the dispatcher queue. + +## Anti-patterns + +- Blocking the UI thread with `.Result` or `.GetAwaiter().GetResult()`. +- Loading all data upfront when only a subset is needed. +- Creating new `HttpClient` instances per request (use `IHttpClientFactory`). +- Using `FindName()` or `VisualTreeHelper` in tight loops. + +## Validation + +- Build & register the MSIX package — see **Build, Run & Deploy** in `.github/agents/Agents.md`. + +### Verification Checklist + +- [ ] No blocking calls on the UI thread +- [ ] `x:Bind` is used instead of `{Binding}` +- [ ] Large lists use virtualization + +## Must Read & Research + +> **Agent Rule:** Before any performance-sensitive change (data binding, layout, collections, async), you **must** fetch and review these references using `fetch_webpage`. Apply what you learn. + +| # | Reference | When to consult | +|---|---|---| +| 1 | [Performance best practices for WinUI 3](https://learn.microsoft.com/en-us/windows/apps/performance/) | Any change touching UI rendering, data loading, or threading | +| 2 | [x:Bind markup extension](https://learn.microsoft.com/en-us/windows/uwp/xaml-platform/x-bind-markup-extension) | Adding or modifying XAML data bindings | +| 3 | [x:Load attribute](https://learn.microsoft.com/en-us/windows/uwp/xaml-platform/x-load-attribute) | Deferring UI element loading | +| 4 | [Optimize XAML layout](https://learn.microsoft.com/en-us/windows/apps/performance/optimize-xaml-layout) | Restructuring XAML panels, reducing visual tree depth | +| 5 | [ListView optimization](https://learn.microsoft.com/en-us/windows/apps/performance/optimize-listview) | Working with lists, collections, or `ItemsRepeater` | + + diff --git a/dev/Templates/Dotnet/templates/blank-app/instructions/security.instructions.md b/dev/Templates/Dotnet/templates/blank-app/instructions/security.instructions.md new file mode 100644 index 0000000000..6eeab880ab --- /dev/null +++ b/dev/Templates/Dotnet/templates/blank-app/instructions/security.instructions.md @@ -0,0 +1,55 @@ +--- +description: 'Security requirements for secrets management, input validation, permissions, and secure coding' +applyTo: '**/*.cs, **/*.appxmanifest' +--- + +# Security + +These rules apply to **every feature and change**. They are not optional add-ons. + +--- + +## Rules + +- **Never hard-code secrets** (API keys, passwords, connection strings) — use environment variables, Windows Credential Manager, or Azure Key Vault. +- Validate and sanitize **all external input** (user input, file content, network responses). +- Use `SecureString` or `PasswordVault` for sensitive data in memory when practical. +- Follow the **principle of least privilege** — request only the permissions the app actually needs in `Package.appxmanifest`. +- Keep NuGet packages up to date — run `dotnet list package --outdated` regularly. +- Enable **code signing** for published MSIX packages. Use the `winapp` CLI rather than hand-rolling `signtool`: + - Generate a development certificate matching the manifest publisher: `winapp cert generate --manifest .\Package.appxmanifest --install`. + - Inspect a cert before signing: `winapp cert info .\devcert.pfx`. + - Sign an existing file: `winapp sign .\MyApp.msix --cert .\devcert.pfx`. + - Build + sign in one step: `winapp pack .\bin\\Release\\win- --cert .\devcert.pfx`. + - Production releases must be signed by a trusted certificate authority -- never ship the development cert. +- When using `HttpClient`, always validate TLS certificates and use HTTPS. +- Never log sensitive data (PII, tokens, passwords). + +## Anti-patterns + +- Storing secrets in `appsettings.json` committed to source control. +- Disabling TLS validation for debugging and forgetting to re-enable it. +- Using `Process.Start` with unsanitized user input. +- Broad `try { } catch (Exception) { }` that swallows errors silently without any logging. + +## Validation + +- Build & register the MSIX package — see **Build, Run & Deploy** in `.github/agents/Agents.md`. +- Check for hard-coded secrets: search for `password`, `apikey`, `secret`, `connectionstring` in `.cs` files. + +### Verification Checklist + +- [ ] No secrets are hard-coded + +## Must Read & Research + +> **Agent Rule:** Before any security-related change (auth, input handling, permissions, HTTP), you **must** fetch and review these references using `fetch_webpage`. Apply what you learn. + +| # | Reference | When to consult | +|---|---|---| +| 1 | [.NET Security Best Practices](https://learn.microsoft.com/en-us/dotnet/standard/security/) | Any code handling credentials, tokens, or sensitive data | +| 2 | [Secure coding guidelines for .NET](https://learn.microsoft.com/en-us/dotnet/standard/security/secure-coding-guidelines) | Input validation, exception handling, type safety | +| 3 | [MSIX Security](https://learn.microsoft.com/en-us/windows/msix/msix-container) | Packaging, signing, or distribution changes | +| 4 | [Package.appxmanifest capabilities](https://learn.microsoft.com/en-us/windows/uwp/packaging/app-capability-declarations) | Adding or modifying app capabilities/permissions | + + diff --git a/dev/Templates/Dotnet/templates/blank-app/instructions/testing.instructions.md b/dev/Templates/Dotnet/templates/blank-app/instructions/testing.instructions.md new file mode 100644 index 0000000000..8a08739ecc --- /dev/null +++ b/dev/Templates/Dotnet/templates/blank-app/instructions/testing.instructions.md @@ -0,0 +1,284 @@ +--- +description: 'Unit testing standards, test project setup, naming, build & run commands' +applyTo: '**/*Tests.cs, **/*Test.cs, **/*.Tests.csproj' +--- + +# Testing — Unit Tests, Build & Run + +Every public method and class must have corresponding unit tests. Tests are not optional. + +--- + +## 1. Test Framework & Project Setup + +### Recommended Stack + +| Component | Package | Purpose | +|---|---|---| +| Test Framework | `MSTest` | Test runner & assertions | +| Mocking | `Moq` | Mock dependencies | +| UI Testing | `Microsoft.Windows.Apps.Test` | WinUI UI automation (optional) | + +### Test Project Setup + +Create a test project alongside the main project: + +``` +/ + / ← Main app project + .Tests/ ← Unit test project +``` + +Test project `.csproj` should reference the main project: + +```xml + + + + + true + enable + false + + + + + + + + + + + + + + +``` + +--- + +## 2. Test Writing Rules + +### What to Test +- **All public methods** in ViewModels, Services, Helpers, and Models. +- **Edge cases** — null inputs, empty collections, boundary values. +- **Error paths** — exception handling, invalid state transitions. +- **Business logic** — calculations, transformations, state management. + +### What NOT to Test (Directly) +- XAML layout / visual rendering (use UI tests for that). +- Framework internals (e.g., `InitializeComponent()`). +- Private methods — test them indirectly through public methods. + +### Test Naming Convention + +Use the pattern: `MethodName_Scenario_ExpectedResult` + +```csharp +[TestMethod] +public void CalculateTotal_WithEmptyCart_ReturnsZero() { } + +[TestMethod] +public void LoadDataAsync_WhenServiceThrows_SetsErrorState() { } + +[TestMethod] +public async Task SaveAsync_WithValidInput_ReturnsTrue() { } +``` + +### Test Structure (AAA Pattern) + +Every test follows **Arrange → Act → Assert**: + +```csharp +[TestMethod] +public void Add_TwoPositiveNumbers_ReturnsSum() +{ + // Arrange + var calculator = new Calculator(); + + // Act + int result = calculator.Add(2, 3); + + // Assert + Assert.AreEqual(5, result); +} +``` + +### ViewModel Testing Example + +```csharp +[TestMethod] +public async Task LoadItemsAsync_OnSuccess_PopulatesItems() +{ + // Arrange + var mockService = new Mock(); + mockService + .Setup(s => s.GetItemsAsync()) + .ReturnsAsync(new List { new("Test") }); + + var viewModel = new MainViewModel(mockService.Object); + + // Act + await viewModel.LoadItemsAsync(); + + // Assert + Assert.AreEqual(1, viewModel.Items.Count); + Assert.IsFalse(viewModel.IsLoading); +} +``` + +--- + +## 3. Test Organization + +### File Structure + +Mirror the main project's folder structure (defined in [winui-best-practices](winui-best-practices.instructions.md)) in the test project. As the main project grows with subfolders under `ViewModels/`, `Services/`, `Views/`, etc., the test project must grow organically in the same way. This alignment enables on-demand test runs scoped to the area you changed: + +``` +/ .Tests/ + Models/ Models/ + User.cs UserTests.cs + ViewModels/ ViewModels/ + MainViewModelTests.cs MainViewModelTests.cs + Settings/ Settings/ + ThemeViewModel.cs ThemeViewModelTests.cs + Services/ Services/ + DataService.cs DataServiceTests.cs + Auth/ Auth/ + AuthService.cs AuthServiceTests.cs + Helpers/ Helpers/ + StringHelper.cs StringHelperTests.cs + Converters/ Converters/ + BoolToVisibilityConverter.cs BoolToVisibilityConverterTests.cs +``` + +### One Test Class per Class Under Test + +```csharp +namespace .Tests.ViewModels; + +[TestClass] +public class MainViewModelTests +{ + // All tests for MainViewModel go here +} +``` + +### Running Tests On-Demand + +After a change, run only the tests related to the affected area instead of the full suite. Detect the platform first (matching the convention in `.github/agents/Agents.md`): + +```powershell +# Run from the test project folder +cd .Tests + +# Detect platform once per session (AMD64 -> x64; ARM64/x86 unchanged) +$arch = $env:PROCESSOR_ARCHITECTURE +$Platform = if ($arch -eq 'AMD64') { 'x64' } else { $arch } + +# Run tests for a specific class +dotnet test -c Debug -p:Platform=$Platform --filter "FullyQualifiedName~MainViewModelTests" + +# Run a single test +dotnet test -c Debug -p:Platform=$Platform --filter "FullyQualifiedName~MainViewModelTests.LoadItemsAsync_OnSuccess_PopulatesItems" + +# Run all tests in a namespace (e.g., all ViewModel tests) +dotnet test -c Debug -p:Platform=$Platform --filter "FullyQualifiedName~Tests.ViewModels" + +# Run tests in a subfolder namespace (e.g., only Settings ViewModels) +dotnet test -c Debug -p:Platform=$Platform --filter "FullyQualifiedName~Tests.ViewModels.Settings" + +# Run the full suite (for cross-cutting changes) +dotnet test -c Debug -p:Platform=$Platform +``` +``` + +--- + +## 4. Test-Specific Commands + +For general build and register commands, see **Build, Run & Deploy** in `.github/agents/Agents.md`. +For on-demand test filtering, see **Running Tests On-Demand** above. + +Below are additional test commands: + +### Build Only the Test Project + +```powershell +cd .Tests +$arch = $env:PROCESSOR_ARCHITECTURE +$Platform = if ($arch -eq 'AMD64') { 'x64' } else { $arch } +dotnet build -c Debug -p:Platform=$Platform +``` + +### Run Tests with Verbose Output + +```powershell +dotnet test -c Debug -p:Platform=$Platform --verbosity normal +``` + +--- + +## 5. Agent Workflow for Tests + +When you write or modify code, follow this sequence: + +1. **Implement the feature or fix** in the main project. +2. **Write unit tests** for every new/changed public method. +3. **Build** — see **Build, Run & Deploy** in `.github/agents/Agents.md`. Fix all errors and warnings. +4. **Run tests** — `dotnet test -c Debug -p:Platform=$Platform` (from the test project folder; detect `$Platform` as shown above) and ensure all pass. +5. **Review** — Confirm tests cover the happy path, edge cases, and error cases. + +### When Modifying Existing Code + +1. **Run existing tests first** to establish a baseline. +2. Make the code change. +3. **Run tests again** — fix any failures. +4. **Add new tests** if the change introduces new behaviour. + +### Coverage Goals + +- Aim for **80%+ code coverage** on business logic (ViewModels, Services). +- 100% coverage of utility/helper methods. +- UI code-behind is exempt from unit test coverage (tested via integration/UI tests). + +--- + +## 6. Common Test Pitfalls + +| Pitfall | Fix | +|---|---| +| Test depends on another test's state | Each test must be fully independent | +| Testing multiple things in one test | One assertion per logical concept | +| Tests pass but don't actually verify anything | Always have meaningful assertions | +| Mocking too much | Mock only external dependencies, not the class under test | +| Testing implementation details | Test behaviour and outcomes, not internal method calls | +| Async tests without `await` | Always `await` async methods and use `async Task` return type | + +--- + +## Validation + +- Build & run tests — see **Build, Run & Deploy** in `.github/agents/Agents.md`. +- Verify all tests pass — zero failures, zero skipped without justification. +- Verify naming follows `MethodName_Scenario_ExpectedResult` pattern. +- Verify AAA structure (Arrange/Act/Assert) in every test method. +- Confirm coverage goals: 80%+ on ViewModels/Services, 100% on helpers. + +--- + +## Must Read & Research + +> **Agent Rule:** Before writing or modifying tests, you **must** fetch and review the relevant references below using `fetch_webpage`. Apply what you learn — do not skip this step. + +| # | Reference | When to consult | +|---|---|---| +| 1 | [Unit testing C# with MSTest](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-mstest) | Setting up test project, writing first tests, MSTest attributes | +| 2 | [Unit testing best practices .NET](https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices) | Every time you write tests — naming, structure, AAA pattern | +| 3 | [Moq Quickstart](https://github.com/devlooped/moq/wiki/Quickstart) | Mocking interfaces, setting up `Returns`/`Throws`, verifying calls | +| 4 | [FluentAssertions Documentation](https://fluentassertions.com/introduction) | Writing expressive assertions (`Should().Be()`, collections, exceptions) | +| 5 | [dotnet test CLI](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-test) | Running tests from terminal, filtering, verbosity options | +| 6 | [Test Explorer in Visual Studio](https://learn.microsoft.com/en-us/visualstudio/test/run-unit-tests-with-test-explorer) | Debugging tests, viewing coverage, understanding test output | + + diff --git a/dev/Templates/Dotnet/templates/blank-app/instructions/windows-apis.instructions.md b/dev/Templates/Dotnet/templates/blank-app/instructions/windows-apis.instructions.md new file mode 100644 index 0000000000..002e776fb7 --- /dev/null +++ b/dev/Templates/Dotnet/templates/blank-app/instructions/windows-apis.instructions.md @@ -0,0 +1,92 @@ +--- +description: 'WinAppSDK & Windows Platform SDK -- API namespace catalog and lookup guidance' +applyTo: '**/*.cs, **/*.xaml, **/*.csproj' +--- + +# Windows APIs -- WinAppSDK & Windows Platform SDK + +## Sample-First Rule + +> **Agent Rule -- MANDATORY:** Before implementing **any** WinAppSDK or Windows Platform SDK API you have not used before, you **must** search the sample repositories below for a working example first. **Do not guess API usage patterns from documentation alone** -- the docs often omit critical details that only the sample code reveals. Search **all** of the following repos, not just one: + +| # | Repository | What it covers | +|---|---|---| +| 1 | [WindowsAppSDK-Samples](https://github.com/microsoft/WindowsAppSDK-Samples) | All WinAppSDK features (AI, windowing, lifecycle, notifications, etc.) | +| 2 | [AI Dev Gallery](https://github.com/microsoft/ai-dev-gallery) | On-device AI/ML patterns, model usage examples | +| 3 | [WinUI-Gallery](https://github.com/microsoft/WinUI-Gallery) | UI control patterns and XAML examples | + +### How to apply + +1. **Find the right API** -- Translate the user's scenario/requirement into common API/programming keywords, then search the API references (Part A-B below) using those keywords to identify which API fits. +2. **Search for samples** -- Once you know which API to use, search each sample repo above for the class name to find a working example. +3. **Study the sample** -- Read the sample's Model / ViewModel / Service layer to understand how the API is actually called -- object lifetime, required parameters, data preparation, error handling. +4. **Adapt** the sample pattern into our MVVM architecture -- don't copy the sample structure wholesale, but match its API call sequence exactly. + +--- + +> **Agent Rule:** Before implementing any feature that involves a platform capability, **consult this file** to check whether a built-in API already exists. Always verify exact class names, method signatures, and availability by following the reference links -- do not guess API shapes. + +--- + +## Part A -- Windows App SDK APIs + +**Full API reference:** + +> **Agent Rule:** Do not rely on a hardcoded namespace list -- the SDK is updated frequently. Instead, **search** the API reference above by converting the user's scenario into common programming keywords. + +### How to search + +1. **Translate** the user's request into API/programming terms. Examples: + - "I want to describe an image" -> search for: `image description`, `ImageDescription`, `describe image` + - "Add a notification" -> search for: `notification`, `toast`, `AppNotification` + - "Pick a file" -> search for: `file picker`, `StoragePicker`, `FileOpenPicker` + - "Make the window always on top" -> search for: `AppWindow`, `presenter`, `compact overlay` +2. **Search** the [WinAppSDK API reference](https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/) using `web_search` or `web_fetch` with those keywords. +3. **Verify** the class/method exists in the SDK version used by this project (check `.csproj` `` for `Microsoft.WindowsAppSDK` version). + +### Key reference links + +| # | Link | When to consult | +|---|---|---| +| 1 | [WinAppSDK API Reference (full)](https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/) | **Always** -- search and look up exact class/method signatures here | +| 2 | [Windows App SDK overview](https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/) | Feature overview, architecture | +| 3 | [Release notes (stable)](https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/stable-channel) | API availability, version support, breaking changes | +| 4 | [Windows AI overview](https://learn.microsoft.com/en-us/windows/ai/) | All AI options: Windows AI APIs, Windows ML, Foundry Local | +| 5 | [Get started with Windows AI APIs](https://learn.microsoft.com/en-us/windows/ai/apis/get-started) | Prerequisites, project setup, first AI call | +| 6 | [Windows ML overview](https://learn.microsoft.com/en-us/windows/ai/new-windows-ml/overview) | Custom ONNX model inference | +| 7 | [Foundry Local](https://learn.microsoft.com/en-us/windows/ai/foundry-local/get-started) | Run OSS LLMs locally | + +--- + +## Part B -- Windows Platform SDK (UWP / WinRT APIs) + +**Full API reference:** + +> **Agent Rule:** The Platform SDK (`Windows.*` namespaces) is very large and constantly evolving. Do not rely on a hardcoded list. **Search** the API reference by translating the user's requirement into programming keywords. + +### How to search + +1. **Translate** the user's request into API/programming terms. Examples: + - "Send a Bluetooth message" -> search for: `Bluetooth`, `RFCOMM`, `BluetoothDevice` + - "Get the user's location" -> search for: `geolocation`, `Geolocator`, `position` + - "Read text from an image" -> search for: `OCR`, `text recognition`, `OcrEngine` + - "Copy to clipboard" -> search for: `clipboard`, `DataTransfer`, `DataPackage` +2. **Search** the [Platform SDK API reference](https://learn.microsoft.com/en-us/uwp/api/) using `web_search` or `web_fetch` with those keywords. +3. **Check for WinAppSDK equivalent** -- some Platform SDK APIs have newer equivalents in Part A. Always prefer the WinAppSDK version when both exist. + +### Key reference links + +| # | Link | When to consult | +|---|---|---| +| 1 | [Platform SDK API Reference (full)](https://learn.microsoft.com/en-us/uwp/api/) | **Search here** for any Windows capability not in WinAppSDK | +| 2 | [Windows SDK downloads](https://developer.microsoft.com/windows/downloads/windows-sdk/) | SDK versions and downloads | + +--- + +## Validation + +- Before implementing any platform feature, confirm the API is available in the current Windows App SDK version by checking the [release notes](https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/stable-channel). +- For features requiring specific hardware (NPU), provide a graceful fallback for unsupported devices. +- When both WinAppSDK and Platform SDK offer a similar API, prefer the WinAppSDK version. + + diff --git a/dev/Templates/Dotnet/templates/blank-app/instructions/winui-best-practices.instructions.md b/dev/Templates/Dotnet/templates/blank-app/instructions/winui-best-practices.instructions.md new file mode 100644 index 0000000000..a8565ac872 --- /dev/null +++ b/dev/Templates/Dotnet/templates/blank-app/instructions/winui-best-practices.instructions.md @@ -0,0 +1,420 @@ +--- +description: 'WinUI 3 / WinAppSDK architecture, MVVM, XAML patterns, DI, theming, and controls guidance' +applyTo: '**/*.cs, **/*.xaml, **/*.csproj' +--- + +# WinUI 3 / WinAppSDK -- Best Practices & Patterns + +This file covers WinUI 3-specific patterns, conventions, and architecture guidance for this project. + +--- + +## 1. Architecture -- MVVM Pattern + +### Overview + +Use **Model-View-ViewModel (MVVM)** for all UI features: + +| Layer | Responsibility | Example | +|---|---|---| +| **Model** | Data structures & business entities | `Item.cs`, `UserProfile.cs` | +| **View** | XAML UI -- layout, styles, animations | `MainPage.xaml` | +| **ViewModel** | UI state, commands, data transformation | `MainViewModel.cs` | +| **Service** | Business logic, data access, navigation | `IDataService.cs`, `NavigationService.cs` | + +### Project Folder Structure + +``` +/ + Models/ -> Data classes + ViewModels/ -> ViewModels (one per page/dialog) + Views/ -> XAML pages and windows + Services/ -> Business logic & platform services + Converters/ -> IValueConverter implementations + Helpers/ -> Static utility methods + Controls/ -> Custom/reusable controls + Strings/ + en-us/ + Resources.resw + Assets/ -> Images, icons, splash screens +``` + +### ViewModel Base + +Use `CommunityToolkit.Mvvm` (recommended) for boilerplate-free ViewModels: + +```xml + + +``` + +```csharp +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; + +public partial class MainViewModel : ObservableObject +{ + [ObservableProperty] + private string _title = string.Empty; + + [ObservableProperty] + private bool _isLoading; + + [RelayCommand] + private async Task LoadDataAsync() + { + IsLoading = true; + try + { + // Load data + } + finally + { + IsLoading = false; + } + } +} +``` + +### View-ViewModel Binding + +```xml + + + + + + + + +