When working on projects related to .net project initialization, apply this domain knowledge.
.NET Project Initialization — Domain Knowledge
Directory.Build.props (Centralized Build Config)
Project Configuration Patterns
Modern .NET (10+)
global.json: Include "test": { "runner": "Microsoft.Testing.Platform" } for .NET 10+
test discovery with Microsoft.Testing.Platform runner.
- MTP vs VSTest conflict: The
global.json MTP runner config requires the test project
to use an MTP-compatible runner package. If using xUnit with xunit.runner.visualstudio
(a VSTest adapter), you must either remove the test runner config from global.json
or switch to xunit.runner.mtp for MTP compatibility.
- Test SDK: Use
Microsoft.NET.Test.Sdk + MSTest/xUnit/NUnit + MTP runner package.
- For AOT-compatible projects:
<IsAotCompatible>true</IsAotCompatible>.
Assembly Version Access
Replace hardcoded version strings with runtime assembly metadata:
// AOT-safe: use typeof(T).Assembly instead of Assembly.GetExecutingAssembly()
// Assembly.GetExecutingAssembly() relies on stack-frame reflection and is NOT AOT-safe
var version = typeof(MyClass).Assembly.GetName().Version;
var infoVersion = typeof(MyClass).Assembly
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?
.InformationalVersion;
This automatically reflects the <Version> set in the csproj.
InformationalVersion includes the SemVer string (e.g., 1.2.3+commit-sha).
WinUI 3 Projects
- SDK:
Microsoft.NET.Sdk (not Microsoft.NET.Sdk.WindowsDesktop).
- TFM:
net10.0-windows10.0.22621 (or appropriate Windows SDK version).
<UseWinUI>true</UseWinUI> enables WinUI 3 support.
<EnableMsixTooling>true</EnableMsixTooling> for MSIX packaging.
Solution Format Migration (.sln → .slnx)
dotnet sln migrate converts a classic .sln to the newer XML .slnx format.
- The generated
.slnx preserves solution folders, build dependencies, platform/config
mappings, project deploy flags, and solution items.
- Validate it builds via MSBuild (which must accept
.slnx) before deleting the old .sln.
- Update CI workflows that reference the
.sln by name — the file name changes.
Toolset Modernization (mixed C#/C++ solutions)
- Bumping to .NET 10 SDK often exposes stale native toolsets: a C++/WinRT project pinned to
PlatformToolset v143 can fail the full build until moved to v145.
- CppWinRT 3.0 changes proxy
.winmd output — verify the metadata project still emits the
expected proxy winmd after upgrading, since downstream WPF/UWP consumers depend on it.
- Investigate what's actually installed (
dotnet --list-sdks, VS version, C++ toolset)
before choosing "latest" — the environment dictates the achievable target.
Windows Service Projects
- SDK:
Microsoft.NET.Sdk.Web for ASP.NET-based services.
- Add
Microsoft.Extensions.Hosting.WindowsServices for Windows service hosting.
COM Server Projects
<EnableComHosting>true</EnableComHosting> for COM server support.
- Platform-specific builds required (not AnyCPU).
NuGet Package Patterns
- Plugin projects: use
<ExcludeAssets>runtime</ExcludeAssets> on host framework references
to avoid bundling the host's assemblies.
- Test projects: full asset inclusion is fine.
- For tools/analyzers:
PrivateAssets="all" prevents transitive dependency.
CI Workflow Patterns (GitHub Actions)
.NET Build + Test
name: CI
on: [push, pull_request]
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- run: dotnet restore
- run: dotnet build --no-restore -c Release
- run: dotnet test --no-build -c Release
MSIX-Specific CI
- MSIX builds may require
msbuild instead of dotnet build.
- Use
microsoft/setup-msbuild@v2 action.
- Build with
-p:Platform=x64 (or ARM64) — not AnyCPU.
- For tests:
dotnet test --project Tests.csproj -p:Platform=x64.
Multi-Platform Matrix
strategy:
matrix:
platform: [x64, ARM64]
steps:
- run: msbuild App.csproj -p:Platform=${{ matrix.platform }} -p:Configuration=Release
copilot-instructions.md Pattern
- Always create
.github/copilot-instructions.md in new repos.
- Include: build/test commands, architecture overview, key conventions, gotchas.
- Update when architecture changes significantly.
Versioning and Changelog
Semantic Versioning (SemVer)
- All projects should follow Semantic Versioning:
MAJOR.MINOR.PATCH.
- MAJOR: incompatible API or behavioral changes.
- MINOR: new functionality that is backward-compatible.
- PATCH: backward-compatible bug fixes.
- Pre-release versions use a hyphen suffix:
1.0.0-alpha, 1.0.0-beta.1.
- Start new projects at
0.1.0 (initial development) or 1.0.0 (first stable release).
Keep a Changelog
- All projects should maintain a
CHANGELOG.md following Keep a Changelog.
- Format:
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/),
and this project adheres to [Semantic Versioning](https://semver.org/).
## [Unreleased]
### Added
- New feature description
### Changed
- Changed behavior description
### Fixed
- Bug fix description
## [1.0.0] - 2026-03-22
### Added
- Initial release
[Unreleased]: https://github.com/owner/repo/compare/v1.0.0...HEAD
[1.0.0]: https://github.com/owner/repo/releases/tag/v1.0.0
- Section types: Added, Changed, Deprecated, Removed, Fixed, Security.
- Always keep an
[Unreleased] section at the top for in-progress work.
- Use comparison links at the bottom for each version.
- When releasing, move
[Unreleased] entries into a new versioned section with the release date.
1---2name: dotnet-project-init3description: Directory.Build.props, CI workflows, project scaffolding, copilot-instructions.md, Keep a Changelog, and Semantic Versioning4---5
6When working on projects related to .net project initialization, apply this domain knowledge.
7
8# .NET Project Initialization — Domain Knowledge
9
10## Directory.Build.props (Centralized Build Config)
11- Place at repo root to share settings across all projects.
12- Common properties to centralize:
13 ```xml
14 <Project>
15 <PropertyGroup>
16 <TargetFramework>net10.0-windows</TargetFramework>
17 <Nullable>enable</Nullable>
18 <ImplicitUsings>enable</ImplicitUsings>
19 <LangVersion>preview</LangVersion>
20 <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
21 </PropertyGroup>
22 </Project>
23 ```
24- Use `<TargetFramework>` conditions in .targets (not .props) — they silently fail
25 for single-targeting projects in .props due to evaluation order.
26- For multi-platform apps (x64/ARM64), set `<Platforms>x64;ARM64</Platforms>`.
27- Set `<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>` for platform-specific builds.
28
29## Project Configuration Patterns
30
31### Modern .NET (10+)
32- `global.json`: Include `"test": { "runner": "Microsoft.Testing.Platform" }` for .NET 10+
33 test discovery with Microsoft.Testing.Platform runner.
34- **MTP vs VSTest conflict**: The `global.json` MTP runner config requires the test project
35 to use an MTP-compatible runner package. If using xUnit with `xunit.runner.visualstudio`
36 (a VSTest adapter), you must either remove the test runner config from `global.json`
37 or switch to `xunit.runner.mtp` for MTP compatibility.
38- Test SDK: Use `Microsoft.NET.Test.Sdk` + MSTest/xUnit/NUnit + MTP runner package.
39- For AOT-compatible projects: `<IsAotCompatible>true</IsAotCompatible>`.
40
41### Assembly Version Access
42Replace hardcoded version strings with runtime assembly metadata:
43```csharp
44// AOT-safe: use typeof(T).Assembly instead of Assembly.GetExecutingAssembly()
45// Assembly.GetExecutingAssembly() relies on stack-frame reflection and is NOT AOT-safe
46var version = typeof(MyClass).Assembly.GetName().Version;
47var infoVersion = typeof(MyClass).Assembly
48 .GetCustomAttribute<AssemblyInformationalVersionAttribute>()?
49 .InformationalVersion;
50```
51This automatically reflects the `<Version>` set in the csproj.
52`InformationalVersion` includes the SemVer string (e.g., `1.2.3+commit-sha`).
53
54### WinUI 3 Projects
55- SDK: `Microsoft.NET.Sdk` (not `Microsoft.NET.Sdk.WindowsDesktop`).
56- TFM: `net10.0-windows10.0.22621` (or appropriate Windows SDK version).
57- `<UseWinUI>true</UseWinUI>` enables WinUI 3 support.
58- `<EnableMsixTooling>true</EnableMsixTooling>` for MSIX packaging.
59
60### Solution Format Migration (.sln → .slnx)
61- `dotnet sln migrate` converts a classic `.sln` to the newer XML `.slnx` format.
62- The generated `.slnx` preserves solution folders, build dependencies, platform/config
63 mappings, project deploy flags, and solution items.
64- Validate it builds via MSBuild (which must accept `.slnx`) before deleting the old `.sln`.
65- **Update CI workflows** that reference the `.sln` by name — the file name changes.
66
67### Toolset Modernization (mixed C#/C++ solutions)
68- Bumping to .NET 10 SDK often exposes stale native toolsets: a C++/WinRT project pinned to
69 `PlatformToolset` **v143** can fail the full build until moved to **v145**.
70- CppWinRT 3.0 changes proxy `.winmd` output — verify the metadata project still emits the
71 expected proxy winmd after upgrading, since downstream WPF/UWP consumers depend on it.
72- Investigate what's actually installed (`dotnet --list-sdks`, VS version, C++ toolset)
73 before choosing "latest" — the environment dictates the achievable target.
74
75### Windows Service Projects
76- SDK: `Microsoft.NET.Sdk.Web` for ASP.NET-based services.
77- Add `Microsoft.Extensions.Hosting.WindowsServices` for Windows service hosting.
78
79### COM Server Projects
80- `<EnableComHosting>true</EnableComHosting>` for COM server support.
81- Platform-specific builds required (not AnyCPU).
82
83## NuGet Package Patterns
84- Plugin projects: use `<ExcludeAssets>runtime</ExcludeAssets>` on host framework references
85 to avoid bundling the host's assemblies.
86- Test projects: full asset inclusion is fine.
87- For tools/analyzers: `PrivateAssets="all"` prevents transitive dependency.
88
89## CI Workflow Patterns (GitHub Actions)
90
91### .NET Build + Test
92```yaml
93name: CI
94on: [push, pull_request]
95concurrency:
96 group: ci-${{ github.ref }}
97 cancel-in-progress: true
98jobs:
99 build:
100 runs-on: windows-latest
101 steps:
102 - uses: actions/checkout@v4
103 - uses: actions/setup-dotnet@v4
104 with:
105 dotnet-version: '10.0.x'
106 - run: dotnet restore
107 - run: dotnet build --no-restore -c Release
108 - run: dotnet test --no-build -c Release
109```
110
111### MSIX-Specific CI
112- MSIX builds may require `msbuild` instead of `dotnet build`.
113- Use `microsoft/setup-msbuild@v2` action.
114- Build with `-p:Platform=x64` (or ARM64) — not AnyCPU.
115- For tests: `dotnet test --project Tests.csproj -p:Platform=x64`.
116
117### Multi-Platform Matrix
118```yaml
119strategy:
120 matrix:
121 platform: [x64, ARM64]
122steps:
123 - run: msbuild App.csproj -p:Platform=${{ matrix.platform }} -p:Configuration=Release
124```
125
126## copilot-instructions.md Pattern
127- Always create `.github/copilot-instructions.md` in new repos.
128- Include: build/test commands, architecture overview, key conventions, gotchas.
129- Update when architecture changes significantly.
130
131## Versioning and Changelog
132
133### Semantic Versioning (SemVer)
134- All projects should follow [Semantic Versioning](https://semver.org/): `MAJOR.MINOR.PATCH`.
135- **MAJOR**: incompatible API or behavioral changes.
136- **MINOR**: new functionality that is backward-compatible.
137- **PATCH**: backward-compatible bug fixes.
138- Pre-release versions use a hyphen suffix: `1.0.0-alpha`, `1.0.0-beta.1`.
139- Start new projects at `0.1.0` (initial development) or `1.0.0` (first stable release).
140
141### Keep a Changelog
142- All projects should maintain a `CHANGELOG.md` following [Keep a Changelog](https://keepachangelog.com/).
143- Format:
144 ```markdown
145 # Changelog
146
147 All notable changes to this project will be documented in this file.
148
149 The format is based on [Keep a Changelog](https://keepachangelog.com/),
150 and this project adheres to [Semantic Versioning](https://semver.org/).
151
152 ## [Unreleased]
153
154 ### Added
155 - New feature description
156
157 ### Changed
158 - Changed behavior description
159
160 ### Fixed
161 - Bug fix description
162
163 ## [1.0.0] - 2026-03-22
164
165 ### Added
166 - Initial release
167
168 [Unreleased]: https://github.com/owner/repo/compare/v1.0.0...HEAD
169 [1.0.0]: https://github.com/owner/repo/releases/tag/v1.0.0
170 ```
171- Section types: **Added**, **Changed**, **Deprecated**, **Removed**, **Fixed**, **Security**.
172- Always keep an `[Unreleased]` section at the top for in-progress work.
173- Use comparison links at the bottom for each version.
174- When releasing, move `[Unreleased]` entries into a new versioned section with the release date.