使用英语阅读

通过


.NET 项目 SDK

新式 .NET 项目与项目软件开发工具包 (SDK) 关联。 每个项目 SDK 都是一组 MSBuild 目标和相关的任务,它们负责编译、打包和发布代码。 引用项目 SDK 的项目有时称为“SDK 样式的项目”。

可用的 SDK

可用的 SDK 包括:

ID 描述 存储库
Microsoft.NET.Sdk .NET SDK https://github.com/dotnet/sdk
Microsoft.NET.Sdk.Web .NET Web SDK https://github.com/dotnet/sdk
Microsoft.NET.Sdk.Razor .NET Razor SDK https://github.com/dotnet/aspnetcore
Microsoft.NET.Sdk.BlazorWebAssembly The .NET Blazor WebAssembly SDK https://github.com/dotnet/aspnetcore
Microsoft.NET.Sdk.Worker .NET 辅助角色服务 SDK https://github.com/dotnet/aspnetcore
Aspire.AppHost.Sdk .NET Aspire SDK https://github.com/dotnet/aspire
MSTest.Sdk MSTest SDK https://github.com/microsoft/testfx

.NET SDK 是 .NET 的基本 SDK。 其他 SDK 引用 .NET SDK,与其他 SDK 关联的项目具有所有可用的 .NET SDK 属性。 例如,Web SDK 依赖于 .NET SDK 和 Razor SDK。

对于 Windows 窗体和 Windows Presentation Foundation (WPF) 项目,请指定 .NET SDK (Microsoft.NET.Sdk),并在项目文件中设置一些其他属性。 有关详细信息,请参阅启用 .NET Desktop SDK

MSBuild SDK(可用于配置和扩展生成)列在 MSBuild SDK 中

你还可以创建自己的 SDK,并通过 NuGet 进行分发。

项目文件

.NET 项目基于 MSBuild 格式。 具有扩展名(如用于 C# 项目的 .csproj 和用于 F# 项目的 .fsproj)的项目文件都是 XML 格式的 。 MSBuild 项目文件的根元素是 Project 元素。 Project 元素有一个可选的 Sdk 属性,该属性指定要使用的 SDK(和版本)。 若要使用 .NET 工具并构建你的代码,请将 Sdk 属性设置为可用 SDK 表中的其中一个 ID。

XML
<Project Sdk="Microsoft.NET.Sdk">
    <!-- Omitted for brevity... -->
</Project>

属性 Project/SdkSdk 元素启用累加 SDK。 请考虑以下示例,其中 .NET Aspire SDK (Aspire.AppHost.Sdk) 将添加到项目顶部 Microsoft.NET.Sdk

XML
<Project Sdk="Microsoft.NET.Sdk">

    <Sdk Name="Aspire.AppHost.Sdk" Version="9.0.0" />
    <!-- Omitted for brevity... -->

</Project>

在前面的项目文件中,这两个 SDK 用于解析具有累加性的依赖项。 有关详细信息,请参阅 .NET Aspire SDK

若要指定来自 NuGet 的 SDK,请在名称末尾包含版本,或者在 global.json 文件中指定名称和版本。

XML
<Project Sdk="MSBuild.Sdk.Extras/2.0.54">
  ...
</Project>

另一种指定 SDK 的方法是使用顶层 Sdk 元素:

XML
<Project>
  <Sdk Name="Microsoft.NET.Sdk" />
  ...
</Project>

以这些方式之一引用 SDK 可以极大地简化 .NET 的项目文件。 在评估项目时,MSBuild 在项目文件的顶部和底部分别为 Sdk.propsSdk.targets 添加隐式导入。

XML
<Project>
  <!-- Implicit top import -->
  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
  ...
  <!-- Implicit bottom import -->
  <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
</Project>

提示

在 Windows 计算机上,Sdk.propsSdk.targets 文件位于 %ProgramFiles%\dotnet\sdk\[version]\Sdks\Microsoft.NET.Sdk\Sdk 文件夹中。

预处理项目文件

使用 dotnet msbuild -preprocess 命令,可以看到 MSBuild 在包含 SDK 及其目标之后所显示的完全扩展的项目。 dotnet msbuild 命令的预处理开关显示导入的文件、文件源及其在生成中的参与情况,而无需实际生成项目。

如果项目有多个目标框架,请将命令的结果指定为 MSBuild 属性,使其仅侧重于框架之一。 例如:

dotnet msbuild -property:TargetFramework=net8.0 -preprocess:output.xml

默认包含和排除的内容

SDK 中定义了 Compile嵌入的资源None默认包含和排除的内容。 与非 SDK .NET 框架项目不同,你无需在项目文件中指定这些项,因为默认设置涵盖了最常见的用例。 此行为使得项目文件更小、更易于理解和手动编辑(如需要)。

下表显示在 .NET SDK 中包含和排除的元素和 glob

元素 包含 glob 排除 glob 删除 glob
Compile **/*.cs(或其他语言扩展名) **/*.user; **/*.*proj; **/*.sln; **/*.vssscc 空值
EmbeddedResource **/*.resx **/*.user; **/*.*proj; **/*.sln; **/*.vssscc 空值
None **/* **/*.user; **/*.*proj; **/*.sln; **/*.vssscc **/*.cs; **/*.resx

备注

默认情况下,由 $(BaseOutputPath)$(BaseIntermediateOutputPath) MSBuild 属性表示的 ./bin./obj 文件夹不包含在 glob 中。 排除由 DefaultItemExcludes 属性表示。

对于 WPF,.NET Desktop SDK 有更多包含和排除项。 有关详细信息,请参阅 WPF 默认包含和排除的内容

如果在项目文件中显式定义这些项中的任何项,可能会出现 NETSDK1022 生成错误。 有关如何解决此错误的信息,请参阅 NETSDK1022:包含重复项

隐式 using 指令

从 .NET 6 开始,隐式 global using 指令将添加到新的 C# 项目中。 这意味着可以使用这些命名空间中定义的类型,而无需指定完全限定的名称或手动添加 using 指令。 隐式方面是指向项目的 obj 目录中生成的文件添加 global using 指令这一事实。

为使用以下 SDK 之一的项目添加隐式 global using 指令:

  • Microsoft.NET.Sdk
  • Microsoft.NET.Sdk.Web
  • Microsoft.NET.Sdk.Worker
  • Microsoft.NET.Sdk.WindowsDesktop

为基于项目 SDK 的一组默认命名空间中的每个命名空间添加 global using 指令。 下表显示了这些默认命名空间。

若要禁用此功能,或要在现有的 C# 项目中启用隐式 global using 指令,可通过 ImplicitUsingsMSBuild 属性实现。

可以通过向项目文件添加 Using 项(或针对 Visual Basic 项目添加 Import 项)来指定其他隐式 global using 指令,例如:

XML
<ItemGroup>
  <Using Include="System.IO.Pipes" />
</ItemGroup>

备注

从 .NET 8 SDK 开始, System.Net.Http 在面向 .NET Framework 时不再包含在Microsoft.NET.Sdk其中。

隐式包引用

如果你的项目以 .NET Standard 1.0-2.0 为目标,则 .NET SDK 会添加对某些元包的隐式引用。 元包是一种基于框架的包,其中只包含对其他包的依赖项。 元包根据项目文件的 TargetFrameworkTargetFrameworks(复数)属性中指定的目标框架被隐式引用。

XML
<PropertyGroup>
  <TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
XML
<PropertyGroup>
  <TargetFrameworks>netstandard2.0;net462</TargetFrameworks>
</PropertyGroup>

如果需要,可以使用 DisableImplicitFrameworkReferences 属性来禁用隐式包引用,并只添加对所需的框架或包的显式引用。

建议:

  • 如果以 .NET Framework 或 .NET Standard 1.0-2.0 为目标,不要通过项目文件中的 <PackageReference> 项添加对 NETStandard.Library 元包的显式引用。 对于 .NET Standard 1.0-2.0 项目,这些元包被隐式引用。 对于 .NET Framework 项目,如果在使用基于 .NET Standard 的 NuGet 包时需要任何版本的 NETStandard.Library,则 NuGet 会自动安装相应版本。
  • 如果在以 .NET Standard 1.0-2.0 为目标时需要特定版本的 NETStandard.Library 元包,则可以使用 <NetStandardImplicitPackageVersion> 属性,并设置所需的版本。

生成事件

在 SDK 样式的项目中,请使用名为 PreBuildPostBuild 的 MSBuild 目标,并设置 PreBuildBeforeTargets 属性或 PostBuildAfterTargets 属性。

XML
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
    <Exec Command="&quot;$(ProjectDir)PreBuildEvent.bat&quot; &quot;$(ProjectDir)..\&quot; &quot;$(ProjectDir)&quot; &quot;$(TargetDir)&quot;" />
</Target>

<Target Name="PostBuild" AfterTargets="PostBuildEvent">
   <Exec Command="echo Output written to $(TargetDir)" />
</Target>

备注

  • 可以为 MSBuild 目标使用任何名称。 但是,Visual Studio IDE 会识别 PreBuildPostBuild 目标,因此通过使用这些名称,可以在 IDE 中编辑命令。
  • 不建议在 SDK 样式的项目中使用属性 PreBuildEventPostBuildEvent,因为无法解析 $(ProjectDir) 这样的宏。 例如,以下代码是不受支持的:
XML
<PropertyGroup>
  <PreBuildEvent>"$(ProjectDir)PreBuildEvent.bat" "$(ProjectDir)..\" "$(ProjectDir)" "$(TargetDir)"</PreBuildEvent>
</PropertyGroup>

自定义生成

可以通过多种方式自定义生成。 建议通过将属性作为参数传递给 msbuilddotnet 命令来重写该属性。 还可以将属性添加到项目文件或 Directory.Build.props 文件中。 有关 .NET 项目的有用属性列表,请参阅 .NET SDK 项目的 MSBuild 参考

提示

从命令行创建新的 Directory.Build.props 文件的一种简单方法是使用存储库根目录中的命令 dotnet new buildprops

自定义目标

.NET 项目可以打包自定义的 MSBuild 目标和属性,以供使用该包的项目使用。 如果要执行以下操作,请使用此类型的可扩展性:

  • 扩展生成过程。
  • 访问生成过程的工件,如生成的文件。
  • 检查调用生成的配置。

通过在项目的生成文件夹中以 <package_id>.targets<package_id>.props(例如 Contoso.Utility.UsefulStuff.targets)的形式放置文件,可以添加自定义生成目标或属性。

以下 XML 是 .csproj 文件中的一个片段,该文件指示 dotnet pack 命令打包的内容。 <ItemGroup Label="dotnet pack instructions"> 元素将目标文件放入包内的生成文件夹中。 <Target Name="CollectRuntimeOutputs" BeforeTargets="_GetPackageFiles"> 元素将程序集和 .json 文件放入生成文件夹 。

XML
<Project Sdk="Microsoft.NET.Sdk">

  ...
  <ItemGroup Label="dotnet pack instructions">
    <Content Include="build\*.targets">
      <Pack>true</Pack>
      <PackagePath>build\</PackagePath>
    </Content>
  </ItemGroup>
  <Target Name="CollectRuntimeOutputs" BeforeTargets="_GetPackageFiles">
    <!-- Collect these items inside a target that runs after build but before packaging. -->
    <ItemGroup>
      <Content Include="$(OutputPath)\*.dll;$(OutputPath)\*.json">
        <Pack>true</Pack>
        <PackagePath>build\</PackagePath>
      </Content>
    </ItemGroup>
  </Target>
  ...

</Project>

若要在项目中使用自定义目标,请添加指向包及其版本的 PackageReference 元素。 与工具不同,自定义目标包包含在消费项目的依赖项闭包中。

你可以配置自定义目标的使用方式。 由于它是 MSBuild 目标,因此会依赖于给定的目标并在另一个目标后运行,也可使用 dotnet msbuild -t:<target-name> 命令手动调用。 若要提供更好的用户体验,可以合并基于项目的工具和自定义目标。 在此方案中,每个项目工具接受所需的任何参数,并将其转换为执行目标所需的 dotnet msbuild 调用。 有关此类协同作用的示例,请访问 dotnet-packer 项目中的 2016 年编程马拉松 MVP 峰会示例存储库。

请参阅