dotnet-project-structure
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese.NET Project Structure and Build Configuration
.NET项目结构与构建配置
When to Use This Skill
何时使用此技能
Use this skill when:
- Setting up a new .NET solution with modern best practices
- Configuring centralized build properties across multiple projects
- Implementing central package version management
- Setting up SourceLink for debugging and NuGet packages
- Automating version management with release notes
- Pinning SDK versions for consistent builds
在以下场景使用此技能:
- 采用现代化最佳实践搭建新的.NET解决方案
- 为多个项目配置集中式构建属性
- 实现集中式包版本管理
- 为调试和NuGet包设置SourceLink
- 通过发布说明自动化版本管理
- 固定SDK版本以确保构建一致性
Related Skills
相关技能
- - Managing local .NET tools with dotnet-tools.json
dotnet-local-tools - - Configuration validation patterns
microsoft-extensions-configuration
- - 使用dotnet-tools.json管理本地.NET工具
dotnet-local-tools - - 配置验证模式
microsoft-extensions-configuration
Solution File Format (.slnx)
解决方案文件格式(.slnx)
The format is the modern XML-based solution file format introduced in .NET 9. It replaces the traditional format.
.slnx.sln.slnx.slnBenefits Over Traditional .sln
相较于传统.sln的优势
| Aspect | .sln (Legacy) | .slnx (Modern) |
|---|---|---|
| Format | Custom text format | Standard XML |
| Readability | GUIDs, cryptic syntax | Clean, human-readable |
| Version control | Hard to diff/merge | Easy to diff/merge |
| Editing | IDE required | Any text editor |
| 方面 | .sln(传统版) | .slnx(现代版) |
|---|---|---|
| 格式 | 自定义文本格式 | 标准XML格式 |
| 可读性 | 包含GUID、语法晦涩 | 清晰易读,适合人类阅读 |
| 版本控制 | 难以对比/合并 | 易于对比/合并 |
| 编辑方式 | 需要IDE | 可使用任何文本编辑器 |
Version Requirements
版本要求
| Tool | Minimum Version |
|---|---|
| .NET SDK | 9.0.200 |
| Visual Studio | 17.13 |
| MSBuild | Visual Studio Build Tools 17.13 |
Note: Starting with .NET 10, creates files by default. In .NET 9, you must explicitly migrate or specify the format.
dotnet new sln.slnx| 工具 | 最低版本 |
|---|---|
| .NET SDK | 9.0.200 |
| Visual Studio | 17.13 |
| MSBuild | Visual Studio Build Tools 17.13 |
注意: 从.NET 10开始,默认创建文件。在.NET 9中,你需要显式迁移或指定格式。
dotnet new sln.slnxExample .slnx File
.slnx文件示例
xml
<Solution>
<Folder Name="/build/">
<File Path="Directory.Build.props" />
<File Path="Directory.Packages.props" />
<File Path="global.json" />
<File Path="NuGet.Config" />
<File Path="README.md" />
</Folder>
<Folder Name="/src/">
<Project Path="src/MyApp/MyApp.csproj" />
<Project Path="src/MyApp.Core/MyApp.Core.csproj" />
</Folder>
<Folder Name="/tests/">
<Project Path="tests/MyApp.Tests/MyApp.Tests.csproj" />
</Folder>
</Solution>xml
<Solution>
<Folder Name="/build/">
<File Path="Directory.Build.props" />
<File Path="Directory.Packages.props" />
<File Path="global.json" />
<File Path="NuGet.Config" />
<File Path="README.md" />
</Folder>
<Folder Name="/src/">
<Project Path="src/MyApp/MyApp.csproj" />
<Project Path="src/MyApp.Core/MyApp.Core.csproj" />
</Folder>
<Folder Name="/tests/">
<Project Path="tests/MyApp.Tests/MyApp.Tests.csproj" />
</Folder>
</Solution>Migrating from .sln to .slnx
从.sln迁移到.slnx
Use the command to convert existing solutions:
dotnet sln migratebash
undefined使用命令转换现有解决方案:
dotnet sln migratebash
undefinedMigrate a specific solution file
迁移指定的解决方案文件
dotnet sln MySolution.sln migrate
dotnet sln MySolution.sln migrate
Or if only one .sln exists in the directory, just run:
如果目录中只有一个.sln文件,直接运行:
dotnet sln migrate
**Important:** Do not keep both `.sln` and `.slnx` files in the same repository. This causes issues with automatic solution detection and can lead to sync problems. After migration, delete the old `.sln` file.
You can also migrate in Visual Studio:
1. Open the solution
2. Select the Solution in Solution Explorer
3. Go to **File > Save Solution As...**
4. Change "Save as type" to **Xml Solution File (*.slnx)**dotnet sln migrate
**重要提示:** 不要在同一仓库中同时保留`.sln`和`.slnx`文件,这会导致自动解决方案检测出现问题,还可能引发同步错误。迁移完成后,请删除旧的`.sln`文件。
你也可以通过Visual Studio进行迁移:
1. 打开解决方案
2. 在解决方案资源管理器中选择解决方案
3. 进入 **文件 > 另存解决方案为...**
4. 将“保存类型”更改为 **Xml解决方案文件 (*.slnx)**Creating a New .slnx Solution
创建新的.slnx解决方案
bash
undefinedbash
undefined.NET 10+: Creates .slnx by default
.NET 10及以上版本:默认创建.slnx文件
dotnet new sln --name MySolution
dotnet new sln --name MySolution
.NET 9: Specify the format explicitly
.NET 9:显式指定格式
dotnet new sln --name MySolution --format slnx
dotnet new sln --name MySolution --format slnx
Add projects (works the same for both formats)
添加项目(两种格式操作相同)
dotnet sln add src/MyApp/MyApp.csproj
undefineddotnet sln add src/MyApp/MyApp.csproj
undefinedRecommendation
推荐建议
If you're using .NET 9.0.200 or later, migrate your solutions to .slnx. The benefits are significant:
- Dramatically fewer merge conflicts (no random GUIDs changing)
- Human-readable and editable in any text editor
- Consistent with modern format
.csproj - Better diff/review experience in pull requests
如果你使用的是.NET 9.0.200或更高版本,请将解决方案迁移到.slnx。 其优势十分显著:
- 大幅减少合并冲突(不会出现随机GUID变更)
- 人类可读,可在任何文本编辑器中编辑
- 与现代化格式保持一致
.csproj - 在拉取请求中拥有更好的对比/审查体验
Directory.Build.props
Directory.Build.props
Directory.Build.propsDirectory.Build.propsComplete Example
完整示例
xml
<Project>
<!-- Metadata -->
<PropertyGroup>
<Authors>Your Team</Authors>
<Company>Your Company</Company>
<!-- Dynamic copyright year - updates automatically -->
<Copyright>Copyright © 2020-$([System.DateTime]::Now.Year) Your Company</Copyright>
<Product>Your Product</Product>
<PackageProjectUrl>https://github.com/yourorg/yourrepo</PackageProjectUrl>
<RepositoryUrl>https://github.com/yourorg/yourrepo</RepositoryUrl>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageTags>your;tags;here</PackageTags>
</PropertyGroup>
<!-- C# Language Settings -->
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoWarn>$(NoWarn);CS1591</NoWarn> <!-- Missing XML comments -->
</PropertyGroup>
<!-- Version Management -->
<PropertyGroup>
<VersionPrefix>1.0.0</VersionPrefix>
<PackageReleaseNotes>See RELEASE_NOTES.md</PackageReleaseNotes>
</PropertyGroup>
<!-- Target Framework Definitions (reusable properties) -->
<PropertyGroup>
<NetStandardLibVersion>netstandard2.0</NetStandardLibVersion>
<NetLibVersion>net8.0</NetLibVersion>
<NetTestVersion>net9.0</NetTestVersion>
</PropertyGroup>
<!-- SourceLink Configuration -->
<PropertyGroup>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
</ItemGroup>
<!-- NuGet Package Assets -->
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)logo.png" Pack="true" PackagePath="\" />
<None Include="$(MSBuildThisFileDirectory)README.md" Pack="true" PackagePath="\" />
</ItemGroup>
<PropertyGroup>
<PackageIcon>logo.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<!-- Global Using Statements -->
<ItemGroup>
<Using Include="System.Collections.Immutable" />
</ItemGroup>
</Project>xml
<Project>
<!-- 元数据 -->
<PropertyGroup>
<Authors>你的团队</Authors>
<Company>你的公司</Company>
<!-- 动态版权年份 - 自动更新 -->
<Copyright>Copyright © 2020-$([System.DateTime]::Now.Year) 你的公司</Copyright>
<Product>你的产品</Product>
<PackageProjectUrl>https://github.com/yourorg/yourrepo</PackageProjectUrl>
<RepositoryUrl>https://github.com/yourorg/yourrepo</RepositoryUrl>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageTags>your;tags;here</PackageTags>
</PropertyGroup>
<!-- C#语言设置 -->
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoWarn>$(NoWarn);CS1591</NoWarn> <!-- 缺少XML注释 -->
</PropertyGroup>
<!-- 版本管理 -->
<PropertyGroup>
<VersionPrefix>1.0.0</VersionPrefix>
<PackageReleaseNotes>参见RELEASE_NOTES.md</PackageReleaseNotes>
</PropertyGroup>
<!-- 目标框架定义(可复用属性) -->
<PropertyGroup>
<NetStandardLibVersion>netstandard2.0</NetStandardLibVersion>
<NetLibVersion>net8.0</NetLibVersion>
<NetTestVersion>net9.0</NetTestVersion>
</PropertyGroup>
<!-- SourceLink配置 -->
<PropertyGroup>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
</ItemGroup>
<!-- NuGet包资产 -->
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)logo.png" Pack="true" PackagePath="\" />
<None Include="$(MSBuildThisFileDirectory)README.md" Pack="true" PackagePath="\" />
</ItemGroup>
<PropertyGroup>
<PackageIcon>logo.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<!-- 全局Using语句 -->
<ItemGroup>
<Using Include="System.Collections.Immutable" />
</ItemGroup>
</Project>Key Patterns
关键模式
Dynamic Copyright Year
动态版权年份
xml
<Copyright>Copyright © 2020-$([System.DateTime]::Now.Year) Your Company</Copyright>Uses MSBuild property functions to insert current year at build time. No manual updates needed.
xml
<Copyright>Copyright © 2020-$([System.DateTime]::Now.Year) 你的公司</Copyright>使用MSBuild属性函数在构建时插入当前年份,无需手动更新。
Reusable Target Framework Properties
可复用目标框架属性
Define target frameworks once, reference everywhere:
xml
<!-- In Directory.Build.props -->
<PropertyGroup>
<NetLibVersion>net8.0</NetLibVersion>
<NetTestVersion>net9.0</NetTestVersion>
</PropertyGroup>
<!-- In MyApp.csproj -->
<PropertyGroup>
<TargetFramework>$(NetLibVersion)</TargetFramework>
</PropertyGroup>
<!-- In MyApp.Tests.csproj -->
<PropertyGroup>
<TargetFramework>$(NetTestVersion)</TargetFramework>
</PropertyGroup>只需定义一次目标框架,即可在各处引用:
xml
<!-- 在Directory.Build.props中 -->
<PropertyGroup>
<NetLibVersion>net8.0</NetLibVersion>
<NetTestVersion>net9.0</NetTestVersion>
</PropertyGroup>
<!-- 在MyApp.csproj中 -->
<PropertyGroup>
<TargetFramework>$(NetLibVersion)</TargetFramework>
</PropertyGroup>
<!-- 在MyApp.Tests.csproj中 -->
<PropertyGroup>
<TargetFramework>$(NetTestVersion)</TargetFramework>
</PropertyGroup>SourceLink for NuGet Packages
针对NuGet包的SourceLink配置
SourceLink enables step-through debugging of NuGet packages:
xml
<PropertyGroup>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<ItemGroup>
<!-- Choose the right provider for your source control -->
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
<!-- Or: Microsoft.SourceLink.AzureRepos.Git -->
<!-- Or: Microsoft.SourceLink.GitLab -->
<!-- Or: Microsoft.SourceLink.Bitbucket.Git -->
</ItemGroup>SourceLink支持对NuGet包进行单步调试:
xml
<PropertyGroup>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<ItemGroup>
<!-- 根据你的源代码管理选择合适的提供方 -->
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
<!-- 或:Microsoft.SourceLink.AzureRepos.Git -->
<!-- 或:Microsoft.SourceLink.GitLab -->
<!-- 或:Microsoft.SourceLink.Bitbucket.Git -->
</ItemGroup>Directory.Packages.props - Central Package Management
Directory.Packages.props - 集中式包管理
Central Package Management (CPM) provides a single source of truth for all NuGet package versions.
集中式包管理(CPM)为所有NuGet包版本提供单一可信来源。
Setup
设置步骤
xml
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<!-- Define version variables for related packages -->
<PropertyGroup>
<AkkaVersion>1.5.35</AkkaVersion>
<AspireVersion>9.1.0</AspireVersion>
</PropertyGroup>
<!-- Application Dependencies -->
<ItemGroup Label="App Dependencies">
<PackageVersion Include="Akka" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Cluster" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Persistence" Version="$(AkkaVersion)" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
</ItemGroup>
<!-- Build/Tooling Dependencies -->
<ItemGroup Label="Build Dependencies">
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
</ItemGroup>
<!-- Test Dependencies -->
<ItemGroup Label="Test Dependencies">
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.1" />
<PackageVersion Include="FluentAssertions" Version="7.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="coverlet.collector" Version="6.0.3" />
</ItemGroup>
</Project>xml
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<!-- 为相关包定义版本变量 -->
<PropertyGroup>
<AkkaVersion>1.5.35</AkkaVersion>
<AspireVersion>9.1.0</AspireVersion>
</PropertyGroup>
<!-- 应用程序依赖项 -->
<ItemGroup Label="App Dependencies">
<PackageVersion Include="Akka" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Cluster" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Persistence" Version="$(AkkaVersion)" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
</ItemGroup>
<!-- 构建/工具依赖项 -->
<ItemGroup Label="Build Dependencies">
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
</ItemGroup>
<!-- 测试依赖项 -->
<ItemGroup Label="Test Dependencies">
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.1" />
<PackageVersion Include="FluentAssertions" Version="7.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="coverlet.collector" Version="6.0.3" />
</ItemGroup>
</Project>Consuming Packages (No Version Needed)
引用包(无需指定版本)
xml
<!-- In MyApp.csproj -->
<ItemGroup>
<PackageReference Include="Akka" />
<PackageReference Include="Akka.Cluster" />
<PackageReference Include="Microsoft.Extensions.Hosting" />
</ItemGroup>
<!-- In MyApp.Tests.csproj -->
<ItemGroup>
<PackageReference Include="xunit" />
<PackageReference Include="FluentAssertions" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
</ItemGroup>xml
<!-- 在MyApp.csproj中 -->
<ItemGroup>
<PackageReference Include="Akka" />
<PackageReference Include="Akka.Cluster" />
<PackageReference Include="Microsoft.Extensions.Hosting" />
</ItemGroup>
<!-- 在MyApp.Tests.csproj中 -->
<ItemGroup>
<PackageReference Include="xunit" />
<PackageReference Include="FluentAssertions" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
</ItemGroup>Benefits
优势
- Single source of truth - All versions in one file
- No version drift - All projects use same versions
- Easy updates - Change once, applies everywhere
- Grouped packages - Version variables for related packages (e.g., all Akka packages)
- 单一可信来源 - 所有版本集中在一个文件中
- 无版本漂移 - 所有项目使用相同版本
- 易于更新 - 一次修改,全局生效
- 分组管理包 - 为相关包设置版本变量(例如所有Akka包)
global.json - SDK Version Pinning
global.json - SDK版本固定
Pin the .NET SDK version for consistent builds across all environments.
json
{
"sdk": {
"version": "9.0.200",
"rollForward": "latestFeature"
}
}固定.NET SDK版本,确保在所有环境中构建一致。
json
{
"sdk": {
"version": "9.0.200",
"rollForward": "latestFeature"
}
}Roll Forward Policies
向前兼容策略
| Policy | Behavior |
|---|---|
| Exact version required |
| Same major.minor, latest patch |
| Same major, latest minor.patch |
| Same major, latest feature band |
| Same major, latest minor |
| Same major, latest minor |
| Latest SDK (not recommended) |
Recommended: - Allows patch updates within the same feature band.
latestFeature| 策略 | 行为 |
|---|---|
| 要求使用精确版本 |
| 相同主版本.次版本,使用最新补丁版本 |
| 相同主版本,使用最新次版本.补丁版本 |
| 相同主版本,使用最新功能带版本 |
| 相同主版本,使用最新次版本 |
| 相同主版本,使用最新次版本 |
| 使用最新SDK(不推荐) |
推荐: - 允许在同一功能带内使用补丁更新。
latestFeatureVersion Management with RELEASE_NOTES.md
基于RELEASE_NOTES.md的版本管理
Release Notes Format
发布说明格式
markdown
undefinedmarkdown
undefined1.2.0 January 15th 2025
1.2.0 2025年1月15日
- Added new feature X
- Fixed bug in Y
- Improved performance of Z
- 新增功能X
- 修复Y中的bug
- 优化Z的性能
1.1.0 December 10th 2024
1.1.0 2024年12月10日
- Initial release with features A, B, C
undefined- 初始版本,包含功能A、B、C
undefinedParsing Script (getReleaseNotes.ps1)
解析脚本(getReleaseNotes.ps1)
powershell
function Get-ReleaseNotes {
param (
[Parameter(Mandatory=$true)]
[string]$MarkdownFile
)
$content = Get-Content -Path $MarkdownFile -Raw
$sections = $content -split "####"
$result = [PSCustomObject]@{
Version = $null
Date = $null
ReleaseNotes = $null
}
if ($sections.Count -ge 3) {
$header = $sections[1].Trim()
$releaseNotes = $sections[2].Trim()
$headerParts = $header -split " ", 2
if ($headerParts.Count -eq 2) {
$result.Version = $headerParts[0]
$result.Date = $headerParts[1]
}
$result.ReleaseNotes = $releaseNotes
}
return $result
}powershell
function Get-ReleaseNotes {
param (
[Parameter(Mandatory=$true)]
[string]$MarkdownFile
)
$content = Get-Content -Path $MarkdownFile -Raw
$sections = $content -split "####"
$result = [PSCustomObject]@{
Version = $null
Date = $null
ReleaseNotes = $null
}
if ($sections.Count -ge 3) {
$header = $sections[1].Trim()
$releaseNotes = $sections[2].Trim()
$headerParts = $header -split " ", 2
if ($headerParts.Count -eq 2) {
$result.Version = $headerParts[0]
$result.Date = $headerParts[1]
}
$result.ReleaseNotes = $releaseNotes
}
return $result
}Version Bump Script (bumpVersion.ps1)
版本更新脚本(bumpVersion.ps1)
powershell
function UpdateVersionAndReleaseNotes {
param (
[Parameter(Mandatory=$true)]
[PSCustomObject]$ReleaseNotesResult,
[Parameter(Mandatory=$true)]
[string]$XmlFilePath
)
$xmlContent = New-Object XML
$xmlContent.Load($XmlFilePath)
# Update VersionPrefix
$versionElement = $xmlContent.SelectSingleNode("//VersionPrefix")
$versionElement.InnerText = $ReleaseNotesResult.Version
# Update PackageReleaseNotes
$notesElement = $xmlContent.SelectSingleNode("//PackageReleaseNotes")
$notesElement.InnerText = $ReleaseNotesResult.ReleaseNotes
$xmlContent.Save($XmlFilePath)
}powershell
function UpdateVersionAndReleaseNotes {
param (
[Parameter(Mandatory=$true)]
[PSCustomObject]$ReleaseNotesResult,
[Parameter(Mandatory=$true)]
[string]$XmlFilePath
)
$xmlContent = New-Object XML
$xmlContent.Load($XmlFilePath)
# 更新VersionPrefix
$versionElement = $xmlContent.SelectSingleNode("//VersionPrefix")
$versionElement.InnerText = $ReleaseNotesResult.Version
# 更新PackageReleaseNotes
$notesElement = $xmlContent.SelectSingleNode("//PackageReleaseNotes")
$notesElement.InnerText = $ReleaseNotesResult.ReleaseNotes
$xmlContent.Save($XmlFilePath)
}Build Script (build.ps1)
构建脚本(build.ps1)
powershell
undefinedpowershell
undefinedLoad helper scripts
加载辅助脚本
. "$PSScriptRoot\scripts\getReleaseNotes.ps1"
. "$PSScriptRoot\scripts\bumpVersion.ps1"
. "$PSScriptRoot\scripts\getReleaseNotes.ps1"
. "$PSScriptRoot\scripts\bumpVersion.ps1"
Parse release notes and update Directory.Build.props
解析发布说明并更新Directory.Build.props
$releaseNotes = Get-ReleaseNotes -MarkdownFile (Join-Path -Path $PSScriptRoot -ChildPath "RELEASE_NOTES.md")
UpdateVersionAndReleaseNotes -ReleaseNotesResult $releaseNotes -XmlFilePath (Join-Path -Path $PSScriptRoot -ChildPath "Directory.Build.props")
Write-Output "Updated to version $($releaseNotes.Version)"
undefined$releaseNotes = Get-ReleaseNotes -MarkdownFile (Join-Path -Path $PSScriptRoot -ChildPath "RELEASE_NOTES.md")
UpdateVersionAndReleaseNotes -ReleaseNotesResult $releaseNotes -XmlFilePath (Join-Path -Path $PSScriptRoot -ChildPath "Directory.Build.props")
Write-Output "已更新至版本 $($releaseNotes.Version)"
undefinedCI/CD Integration
CI/CD集成
yaml
undefinedyaml
undefinedGitHub Actions example
GitHub Actions示例
-
name: Update version from release notes shell: pwsh run: ./build.ps1
-
name: Build run: dotnet build -c Release
-
name: Pack with tag version run: dotnet pack -c Release /p:PackageVersion=${{ github.ref_name }}
-
name: Push to NuGet run: dotnet nuget push **/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json
----
name: 从发布说明更新版本 shell: pwsh run: ./build.ps1
-
name: 构建 run: dotnet build -c Release
-
name: 使用标签版本打包 run: dotnet pack -c Release /p:PackageVersion=${{ github.ref_name }}
-
name: 推送到NuGet run: dotnet nuget push **/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json
---NuGet.Config
NuGet.Config
Configure NuGet sources and behavior:
xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<solution>
<add key="disableSourceControlIntegration" value="true" />
</solution>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<!-- Add private feeds if needed -->
<!-- <add key="MyCompany" value="https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json" /> -->
</packageSources>
</configuration>Key Settings:
- - Remove inherited/default sources for reproducible builds
<clear /> - - Prevents TFS/Git integration issues
disableSourceControlIntegration
配置NuGet源和行为:
xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<solution>
<add key="disableSourceControlIntegration" value="true" />
</solution>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<!-- 如有需要,添加私有源 -->
<!-- <add key="MyCompany" value="https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json" /> -->
</packageSources>
</configuration>关键设置:
- - 移除继承的/默认源,确保构建可复现
<clear /> - - 避免TFS/Git集成问题
disableSourceControlIntegration
Complete Project Structure
完整项目结构
MySolution/
├── .config/
│ └── dotnet-tools.json # Local .NET tools
├── .github/
│ └── workflows/
│ ├── pr-validation.yml # PR checks
│ └── release.yml # NuGet publishing
├── scripts/
│ ├── getReleaseNotes.ps1 # Parse RELEASE_NOTES.md
│ └── bumpVersion.ps1 # Update Directory.Build.props
├── src/
│ ├── MyApp/
│ │ └── MyApp.csproj
│ └── MyApp.Core/
│ └── MyApp.Core.csproj
├── tests/
│ └── MyApp.Tests/
│ └── MyApp.Tests.csproj
├── Directory.Build.props # Centralized build config
├── Directory.Packages.props # Central package versions
├── MySolution.slnx # Modern solution file
├── global.json # SDK version pinning
├── NuGet.Config # Package source config
├── build.ps1 # Build orchestration
├── RELEASE_NOTES.md # Version history
├── README.md # Project documentation
└── logo.png # Package iconMySolution/
├── .config/
│ └── dotnet-tools.json # 本地.NET工具
├── .github/
│ └── workflows/
│ ├── pr-validation.yml # PR检查
│ └── release.yml # NuGet发布
├── scripts/
│ ├── getReleaseNotes.ps1 # 解析RELEASE_NOTES.md
│ └── bumpVersion.ps1 # 更新Directory.Build.props
├── src/
│ ├── MyApp/
│ │ └── MyApp.csproj
│ └── MyApp.Core/
│ └── MyApp.Core.csproj
├── tests/
│ └── MyApp.Tests/
│ └── MyApp.Tests.csproj
├── Directory.Build.props # 集中式构建配置
├── Directory.Packages.props # 集中式包版本管理
├── MySolution.slnx # 现代化解决方案文件
├── global.json # SDK版本固定
├── NuGet.Config # 包源配置
├── build.ps1 # 构建编排脚本
├── RELEASE_NOTES.md # 版本历史
├── README.md # 项目文档
└── logo.png # 包图标Quick Reference
快速参考
| File | Purpose |
|---|---|
| Modern XML solution file |
| Centralized build properties |
| Central package version management |
| SDK version pinning |
| Package source configuration |
| Version history (parsed by build) |
| Build orchestration script |
| Local .NET tools |
| 文件 | 用途 |
|---|---|
| 现代化XML解决方案文件 |
| 集中式构建属性 |
| 集中式包版本管理 |
| SDK版本固定 |
| 包源配置 |
| 版本历史(由构建脚本解析) |
| 构建编排脚本 |
| 本地.NET工具 |