使用 MSBuild 创建 NuGet 包

从代码中创建 NuGet 包时,会将该功能打包到一个组件中,该组件可以与任意数量的其他开发人员共享和使用。 本文介绍如何使用 MSBuild 创建包。 MSBuild 预安装了包含 NuGet 的所有 Visual Studio 工作负荷。 此外,还可以通过 dotnet CLI 借助 dotnet msbuild 来使用 MSBuild。

对于使用 SDK 样式格式的 .NET Core 和 .NET Standard 项目,以及任何其他 SDK 样式项目,NuGet 直接使用项目文件中的信息创建包。 对于使用 <PackageReference> 的非 SDK 样式的项目,NuGet 还使用项目文件来创建包。

默认情况下,SDK 样式的项目具有可用的包功能。 对于非 SDK 样式的 PackageReference 项目,需要将 NuGet.Build.Tasks.Pack 包添加到项目依赖项中。 有关 MSBuild 包目标的详细信息,请参阅作为 MSBuild 目标的 NuGet 包和还原

用于创建包的命令 msbuild -t:pack,其功能相当于 dotnet pack

重要

本主题适用于 SDK 样式的项目(通常是 .NET Core 和 .NET Standard 项目)以及使用 PackageReference 的非 SDK 样式的项目。

设置属性

创建包需要以下属性。

  • PackageId,包标识符,在托管包的库中必须是唯一的。 如果未指定,默认值为 AssemblyName
  • Version,窗体 Major.Minor.Patch[-Suffix] 中特定的版本号,其中 -Suffix 标识预发布版本。 如果未指定,默认值为 1.0.0。
  • 包标题应出现在主机上(例如 nuget.org)
  • Authors,作者和所有者信息。 如果未指定,默认值为 AssemblyName
  • Company,公司名称。 如果未指定,默认值为 AssemblyName

此外,如要打包使用 PackageReference 的非 SDK 类项目,则需要满足以下要求:

  • PackageOutputPath(调用 pack 时生成的包的输出文件夹)。

在 Visual Studio 中,可以在项目属性中设置这些值(在解决方案资源管理器中右键单击项目,选择“属性”,然后选择“包”选项卡)。 也可以直接在项目文件 (.csproj) 中设置这些属性

<PropertyGroup>
  <PackageId>ClassLibDotNetStandard</PackageId>
  <Version>1.0.0</Version>
  <Authors>your_name</Authors>
  <Company>your_company</Company>
</PropertyGroup>

重要

为包提供一个在 nuget.org 中唯一或你使用的任何包资源的标识符。

以下示例显示了包含这些属性的简单、完整的项目文件。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <PackageId>ClassLibDotNetStandard</PackageId>
    <Version>1.0.0</Version>
    <Authors>your_name</Authors>
    <Company>your_company</Company>
  </PropertyGroup>
</Project>

另外,还可以设置可选属性,例如 TitlePackageDescriptionPackageTags,如 MSBuild 包目标控制依赖项资产NuGet 元数据属性中所述。

注意

对于面向公共使用而生成的包,请特别注意 PackageTags 属性,因为这些标记可帮助其他人查找包并了解其用途。

有关声明依赖项并指定版本号的详细信息,请参阅项目文件中的包引用包版本控制。 还可以使用 <IncludeAssets><ExcludeAssets> 特性直接在包中呈现依赖项的资产。 有关详细信息,请参阅控制依赖项资产

添加可选说明字段

包的可选说明显示在包 nuget.org 页的“自述文件”选项卡上。 说明从项目文件的 <Description> 中或 .nuspec 文件$description 中拉取。

以下示例显示 .NET 包的 .csproj 文件中的 Description

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <PackageId>Azure.Storage.Blobs</PackageId>
    <Version>12.4.0</Version>
    <PackageTags>Microsoft Azure Storage Blobs;Microsoft;Azure;Blobs;Blob;Storage;StorageScalable</PackageTags>
    <Description>
      This client library enables working with the Microsoft Azure Storage Blob service for storing binary and text data.
      For this release see notes - https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/storage/Azure.Storage.Blobs/README.md and https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/storage/Azure.Storage.Blobs/CHANGELOG.md
      in addition to the breaking changes https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/storage/Azure.Storage.Blobs/BreakingChanges.txt
      Microsoft Azure Storage quickstarts and tutorials - https://learn.microsoft.com/azure/storage/
      Microsoft Azure Storage REST API Reference - https://learn.microsoft.com/rest/api/storageservices/
      REST API Reference for Blob Service - https://learn.microsoft.com/rest/api/storageservices/blob-service-rest-api
    </Description>
  </PropertyGroup>
</Project>

选择唯一的包标识符并设置版本号

包标识符和版本号唯一标识包中包含的确切代码。

按照以下最佳做法创建包标识符:

  • 该标识符必须在 nuget.org 和承载包的所有其他位置中是唯一的。 为了避免冲突,最好使用公司名作为标识符的第一部分。

  • 使用点表示法遵循类似于 .NET 命名空间的命名规则。 例如,使用 Contoso.Utility.UsefulStuff 而不是 Contoso-Utility-UsefulStuffContoso_Utility_UsefulStuff。 如果将包标识符与代码使用的命名空间匹配,这对使用者也很有帮助。

  • 如果生成展示如何使用另一个包的示例代码包,请附加 .Sample 作为标识符的后缀,就像 Contoso.Utility.UsefulStuff.Sample 中一样。

    示例包依赖于原始包。 创建示例包时,请添加值为 contentFiles<IncludeAssets>。 在内容文件夹中,排列名为 \Samples\<标识符>的文件夹中的示例代码,例如 \Samples\Contoso.Utility.UsefulStuff.Sample

遵循以下最佳做法设置包版本:

  • 一般情况下,将包版本设置为与项目或程序集版本相匹配,但这不是必须的。 如果将包限制为单个程序集,那么匹配版本很简单。 解析依赖项时,NuGet 自己处理包版本而不是程序集版本。

  • 如果使用非标准版本方案,请确保考虑使用 NuGet 版本控制规则,如包版本控制中所述。 NuGet 主要与语义化版本控制 2.0.0兼容。

注意

有关依赖项解析的详细信息,请参阅使用 PackageReference 进行依赖项解析。 有关可帮助你了解版本控制的信息,请参阅以下系列博客文章:

添加 NuGet.Build.Tasks.Pack 包

如果将 MSBuild 与非 SDK 样式项目和 PackageReference 一起使用,请将 NuGet.Build.Tasks.Pack 包添加到项目中。

  1. 打开项目文件并在 <PropertyGroup> 元素后面添加以下内容:

    <ItemGroup>
      <!-- ... -->
      <PackageReference Include="NuGet.Build.Tasks.Pack" Version="6.7.0" PrivateAssets="all" />
      <!-- ... -->
    </ItemGroup>
    
  2. 打开开发人员命令提示符(在“搜索”框中,键入“开发人员命令提示符”)

    用户通常习惯从“开始”菜单中启动“适用于 Visual Studio 的开发人员命令提示符”,因为它将使用 MSBuild 的所有必需路径进行配置

  3. 切换到包含项目文件的文件夹,然后键入以下命令以安装 NuGet.Build.Tasks.Pack 包。

    # Uses the project file in the current folder by default
    msbuild -t:restore
    

    确保 MSBuild 输出指示生成已成功完成。

运行 msbuild -t:pack 命令

若要从项目中生成 NuGet 包(.nupkg 文件),运行 msbuild -t:pack 命令,它也会自动生成项目:

在 Visual Studio 开发人员命令提示处,键入以下命令:

# Uses the project file in the current folder by default
msbuild -t:pack

输出将显示 .nupkg 文件的路径。

Microsoft (R) Build Engine version 16.1.76+g14b0a930a7 for .NET Framework
Copyright (C) Microsoft Corporation. All rights reserved.

Build started 8/5/2019 3:09:15 PM.
Project "C:\Users\username\source\repos\ClassLib_DotNetStandard\ClassLib_DotNetStandard.csproj" on node 1 (pack target(s)).
GenerateTargetFrameworkMonikerAttribute:
Skipping target "GenerateTargetFrameworkMonikerAttribute" because all output files are up-to-date with respect to the input files.
CoreCompile:
  ...
CopyFilesToOutputDirectory:
  Copying file from "C:\Users\username\source\repos\ClassLib_DotNetStandard\obj\Debug\netstandard2.0\ClassLib_DotNetStandard.dll" to "C:\Use
  rs\username\source\repos\ClassLib_DotNetStandard\bin\Debug\netstandard2.0\ClassLib_DotNetStandard.dll".
  ClassLib_DotNetStandard -> C:\Users\username\source\repos\ClassLib_DotNetStandard\bin\Debug\netstandard2.0\ClassLib_DotNetStandard.dll
  Copying file from "C:\Users\username\source\repos\ClassLib_DotNetStandard\obj\Debug\netstandard2.0\ClassLib_DotNetStandard.pdb" to "C:\Use
  rs\username\source\repos\ClassLib_DotNetStandard\bin\Debug\netstandard2.0\ClassLib_DotNetStandard.pdb".
GenerateNuspec:
  Successfully created package 'C:\Users\username\source\repos\ClassLib_DotNetStandard\bin\Debug\AppLogger.1.0.0.nupkg'.
Done Building Project "C:\Users\username\source\repos\ClassLib_DotNetStandard\ClassLib_DotNetStandard.csproj" (pack target(s)).

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:01.21

在生成期间自动生成包

若要在生成和还原项目时自动运行 msbuild -t:pack,请将以下行添加到 <PropertyGroup> 中的项目文件内:

<GeneratePackageOnBuild>true</GeneratePackageOnBuild>

在解决方案上运行 msbuild -t:pack 时,会打包解决方案中可打包的所有项目(<IsPackable> 属性设置为 true)。

注意

自动生成包时,打包时间会增加项目的生成时间。

测试包安装

发布包前,通常需要测试将包安装到项目的过程。 测试确保所有文件一定在项目中正确的位置结束。

可以在 Visual Studio 中手动测试安装,或是使用常规包安装步骤在命令行上测试。

重要

包是不可变的。 如果更正了问题,请更改包的内容并再次打包,重新测试时,仍将使用旧版本的包,直到清除全局包文件夹。 在测试每次生成时不使用唯一预发布标签的包时,这尤为重要。

后续步骤

创建包(.nupkg 文件)后,可以将其发布到选择的库,如发布包中所述。

你可能还希望扩展包的功能,或者支持其他方案,如以下主题所述:

最后,有需要注意的其他包类型: