mcpField
P
project-structure

project-structure

github.com/wshaddix开发86536 次安装35 周前更新
代码仓库

关于 project-structure

面向 .NET 团队的解决方案结构与构建配置技能,涵盖共享 MSBuild 设置、集中管理 NuGet 版本、SDK 固定、确定性构建和发布版本管理。

主要功能

  1. 01规划解决方案和项目布局
  2. 02集中配置 MSBuild 属性
  3. 03集中管理 NuGet 版本
  4. 04用 global.json 固定 SDK 版本
  5. 05配置确定性构建
  6. 06根据发布说明管理版本

适用场景

  1. 01搭建新的 .NET 解决方案
  2. 02统一多个项目的配置
  3. 03保持依赖包版本一致
  4. 04确保 CI 还原与构建可复现

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/wshaddix/dotnet-skills --skill project-structure

安装后在 Claude Code 中输入/project-structure确认已加载。

详细介绍

.NET 项目结构与构建配置

何时使用此技能

在以下情况下使用此技能:

  • 使用现代最佳实践设置新的 .NET 解决方案
  • 为多个项目配置集中式构建属性
  • 实施中央包版本管理
  • 为调试和 NuGet 包设置 SourceLink
  • 使用发布说明自动管理版本
  • 固定 SDK 版本以确保构建一致

推荐的解决方案布局

MyApp/
├── .config/
│   └── dotnet-tools.json           # Local .NET tools
├── .editorconfig
├── .gitignore
├── global.json
├── nuget.config
├── Directory.Build.props
├── Directory.Build.targets
├── Directory.Packages.props
├── MyApp.slnx                       # .NET 9+ SDK / VS 17.13+
├── src/
│   ├── MyApp.Core/
│   │   └── MyApp.Core.csproj
│   ├── MyApp.Api/
│   │   ├── MyApp.Api.csproj
│   │   ├── Program.cs
│   │   └── appsettings.json
│   └── MyApp.Infrastructure/
│       └── MyApp.Infrastructure.csproj
└── tests/
    ├── MyApp.UnitTests/
    │   └── MyApp.UnitTests.csproj
    └── MyApp.IntegrationTests/
        └── MyApp.IntegrationTests.csproj

关键原则:

  • 将 src/ 和 tests/ 目录分开
  • 每个关注点对应一个项目(Core/Domain、Infrastructure、API/Host)
  • 在仓库根目录放置解决方案文件
  • 在仓库根目录集中放置所有共享构建配置

解决方案文件格式

.slnx(现代格式 — .NET 9+)

基于 XML 的解决方案格式,易于阅读且便于比较差异。需要 .NET 9+ SDK 或 Visual Studio 17.13+。

<Solution>
  <Folder Name="/build/">
    <File Path="Directory.Build.props" />
    <File Path="Directory.Packages.props" />
    <File Path="global.json" />
    <File Path="NuGet.Config" />
  </Folder>
  <Folder Name="/src/">
    <Project Path="src/MyApp.Core/MyApp.Core.csproj" />
    <Project Path="src/MyApp.Api/MyApp.Api.csproj" />
    <Project Path="src/MyApp.Infrastructure/MyApp.Infrastructure.csproj" />
  </Folder>
  <Folder Name="/tests/">
    <Project Path="tests/MyApp.UnitTests/MyApp.UnitTests.csproj" />
    <Project Path="tests/MyApp.IntegrationTests/MyApp.IntegrationTests.csproj" />
  </Folder>
</Solution>
从 .sln 迁移到 .slnx
dotnet sln MySolution.sln migrate

重要: 不要在同一仓库中同时保留 .sln 和 .slnx 文件。

创建新的 .slnx 解决方案
# .NET 10+: Creates .slnx by default
dotnet new sln --name MySolution

# .NET 9: Specify the format explicitly
dotnet new sln --name MySolution --format slnx

dotnet sln add src/MyApp/MyApp.csproj
优势
  • 大幅减少合并冲突
  • 易于阅读和编辑
  • 与现代 .csproj 格式保持一致
  • 在拉取请求中更便于比较差异和审查

Directory.Build.props

应用于目录子树中所有项目的共享 MSBuild 属性。

<Project>
  
  <PropertyGroup>
    <Authors>Your Team</Authors>
    <Company>Your Company</Company>
    <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>
  </PropertyGroup>

  
  <PropertyGroup>
    <LangVersion>latest</LangVersion>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
    <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
    <AnalysisLevel>latest-all</AnalysisLevel>
    <NoWarn>$(NoWarn);CS1591</NoWarn>
  </PropertyGroup>

  
  <PropertyGroup>
    <NetStandardLibVersion>netstandard2.0</NetStandardLibVersion>
    <NetLibVersion>net8.0</NetLibVersion>
    <NetTestVersion>net9.0</NetTestVersion>
  </PropertyGroup>

  
  <PropertyGroup>
    <PublishRepositoryUrl>true</PublishRepositoryUrl>
    <EmbedUntrackSources>true</EmbedUntrackSources>
    <IncludeSymbols>true</IncludeSymbols>
    <SymbolPackageFormat>snupkg</SymbolPackageFormat>
    <DebugType>embedded</DebugType>
    <ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
  </ItemGroup>

  
  <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>

  
  <ItemGroup>
    <Using Include="System.Collections.Immutable" />
  </ItemGroup>
</Project>
嵌套的 Directory.Build.props

内部文件不会自动导入外部文件:


<Project>
  <Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
  <PropertyGroup>
    
  </PropertyGroup>
</Project>

Directory.Build.targets

在项目评估之后导入。用于:

  • 共享分析器包引用
  • 自定义构建目标
  • 基于项目类型的条件逻辑
<Project>
  <ItemGroup>
    <PackageReference Include="Meziantou.Analyzer" PrivateAssets="all" />
    <PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" PrivateAssets="all" />
  </ItemGroup>
</Project>

Directory.Packages.props - 中央包管理

CPM 在仓库根目录集中管理所有 NuGet 包版本。各个 .csproj 文件引用包时无需指定 Version 属性。

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
    <CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
  </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="Microsoft.Extensions.Hosting" Version="9.0.0" />
  </ItemGroup>

  <ItemGroup Label="Test Dependencies">
    <PackageVersion Include="xunit.v3" Version="3.2.2" />
    <PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
    <PackageVersion Include="FluentAssertions" Version="7.0.0" />
    <PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
    <PackageVersion Include="coverlet.collector" Version="8.0.0" />
  </ItemGroup>

  <ItemGroup Label="Build Dependencies">
    <PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
  </ItemGroup>
</Project>
使用包(无需指定版本)

<ItemGroup>
  <PackageReference Include="Akka" />
  <PackageReference Include="Microsoft.Extensions.Hosting" />
</ItemGroup>
版本覆盖
<PackageReference Include="Newtonsoft.Json" VersionOverride="13.0.3" />

.editorconfig

将其放在仓库根目录,以强制执行一致的代码风格:

root = true

[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.{csproj,props,targets,xml,json,yml,yaml}]
indent_size = 2

[*.cs]
csharp_style_namespace_declarations = file_scoped:warning
csharp_prefer_braces = true:warning
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
dotnet_style_require_accessibility_modifiers = always:warning
csharp_style_prefer_pattern_matching = true:suggestion
csharp_style_prefer_switch_expression = true:suggestion
csharp_using_directive_placement = outside_namespace:warning
dotnet_sort_system_directives_first = true

dotnet_naming_rule.private_fields_should_be_camel_case.symbols = private_fields
dotnet_naming_rule.private_fields_should_be_camel_case.style = camel_case_underscore
dotnet_naming_rule.private_fields_should_be_camel_case.severity = warning
dotnet_naming_symbols.private_fields.applicable_kinds = field
dotnet_naming_symbols.private_fields.applicable_accessibilities = private
dotnet_naming_style.camel_case_underscore.required_prefix = _
dotnet_naming_style.camel_case_underscore.capitalization = camel_case

global.json - 固定 SDK 版本

{
  "sdk": {
    "version": "9.0.200",
    "rollForward": "latestFeature"
  }
}
回滚策略
策略行为
disable必须使用完全匹配的版本
patch主版本和次版本相同,使用最新补丁版本
feature主版本相同,使用最新次版本和补丁版本
latestFeature主版本相同,使用最新功能带
minor主版本相同,使用最新次版本
latestMinor主版本相同,使用最新次版本
major使用最新 SDK(不推荐)

建议: 使用 latestFeature,允许在同一功能带内更新补丁版本。


nuget.config

配置包源和安全性:

<?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" />
  </packageSources>

  <packageSourceMapping>
    <packageSource key="nuget.org">
      <package pattern="*" />
    </packageSource>
  </packageSourceMapping>
</configuration>

<clear />、显式源和 <packageSourceMapping> 组合使用的模式可防止供应链攻击。

配置私有源:

<packageSources>
  <clear />
  <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
  <add key="internal" value="https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json" />
</packageSources>
<packageSourceMapping>
  <packageSource key="nuget.org">
    <package pattern="*" />
  </packageSource>
  <packageSource key="internal">
    <package pattern="MyCompany.*" />
  </packageSource>
</packageSourceMapping>

NuGet 审计

.NET 9+ 默认启用 NuGetAudit:

<PropertyGroup>
  <NuGetAudit>true</NuGetAudit>
  <NuGetAuditLevel>low</NuGetAuditLevel>
  <NuGetAuditMode>all</NuGetAuditMode>
</PropertyGroup>

锁定文件

启用确定性还原:

<PropertyGroup>
  <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>

在 CI 中:

dotnet restore --locked-mode

SourceLink 和确定性构建

适用于发布到 NuGet 的库:

<PropertyGroup>
  <PublishRepositoryUrl>true</PublishRepositoryUrl>
  <EmbedUntrackSources>true</EmbedUntrackSources>
  <DebugType>embedded</DebugType>
  <ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild>
</PropertyGroup>
<ItemGroup>
  <PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="all" />
</ItemGroup>

使用 RELEASE_NOTES.md 管理版本

#### 1.2.0 January 15th 2025 ####

- Added new feature X
- Fixed bug in Y

#### 1.1.0 December 10th 2024 ####

- Initial release
CI/CD 集成
- 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 }}

快速参考

文件用途
MySolution.slnx现代 XML 解决方案文件
Directory.Build.props集中式构建属性
Directory.Packages.props中央包版本管理
global.json固定 SDK 版本
NuGet.Config包源配置
RELEASE_NOTES.md版本历史
.editorconfig强制执行代码风格
.config/dotnet-tools.json本地 .NET 工具

参考资料

评论

支持 Markdown