通过


使用 nuget.exe CLI 创建包

无论包的作用是什么或它包含的代码,都可以使用命令行接口(CLI)工具 nuget.exe 之一,或者 dotnet.exe将该功能打包到可以与其他开发人员共享和使用的组件中。 若要安装 NuGet CLI 工具,请参阅 安装 NuGet 客户端工具。 Visual Studio不会自动包含 CLI 工具。

从技术上说,NuGet 包是一个 ZIP 文件,已重命名为扩展名 .nupkg ,其内容与某些约定匹配。 本文介绍创建满足这些约定的包的详细过程。

打包以编译的代码(程序集)、符号和其他要作为包传递的文件开头。 有关打包过程的概述,请参阅 包创建工作流。 此过程与编译或生成进入包的文件无关。 但是,可以从项目文件中的信息进行绘制,使编译的程序集和包保持同步。

重要

本文适用于非 SDK 样式项目,通常是使用 Visual Studio 2017 及更高版本和 NuGet 4.0+ .NET Core 和 .NET Standard 项目以外的项目。

确定要打包的程序集

大多数常规用途包包含一个或多个程序集,其他开发人员可以在自己的项目中使用这些程序集。

一般情况下,最好为每个 NuGet 包创建一个程序集,前提是每个程序集独立有用。 例如,请考虑以下涉及一个名为 Utilities.dll 的程序集,该程序集依赖于名为 Parser.dll的程序集:

  • 如果 Parser.dll 本身很有用,请为 Utilities.dll 创建一个包,一个用于 Parser.dll。 这样,开发人员就可以独立于 Utilities.dll 使用 Parser.dll

  • 如果 Parser.dll 包含仅由 Utilities.dll使用的代码,那么可以在同一包中保留 Parser.dll。 通常,如果库由多个不独立有用的程序集组成,则最好将它们合并到一个包中。

  • 如果 Utilities.dll 还依赖于 Utilities.resources.dll,并且 Utilities.resources.dll 本身没有用处,请将两者放在同一个包中。

资源(如前面的示例中 的Utilities.resources.dll 程序集)是一种特殊情况。 安装包到项目中时,NuGet 会自动将程序集引用添加到包的 DLL,但不包括 命名为 .resources.dll 的 DLL,因为这些 DLL 被假定为本地化的卫星程序集。 有关库的本地化版本的详细信息,请参阅 创建本地化的 NuGet 包。 因此,请避免对包含基本包代码的文件使用 .resources.dll

如果库包含组件对象模型 (COM) 互操作程序集,请遵循 “创建包含 COM 互操作程序集的 NuGet 包”中的其他准则。

.nuspec 文件的角色和结构

了解要打包的文件时,下一步是在 .nuspec XML 文件中创建包清单。

清单:

  • 描述包的内容,并包含在包中。
  • 驱动包的创建,并告知 NuGet 如何将包安装到项目中。 例如,清单标识其他包依赖项,以便 NuGet 也可以在安装主包时安装这些依赖项。
  • 包含本节其余部分中所述的必需属性和可选属性。 有关详细信息,包括此处未提及的其他属性,请参阅 .nuspec 参考

清单中需要以下属性:

  • 包标识符,该标识符在承载包的库中必须唯一
  • Major.Minor.Patch[-Suffix] 中的特定版本号,其中 -Suffix 标识预发行版本
  • 程序包标题,因为它应出现在主机上(如 nuget.org)
  • 作者信息
  • 包裹的详细描述

以下属性是常见的可选属性:

  • 发行说明。
  • 版权信息。
  • 在 Visual Studio 中的程序包管理器 UI的简短说明。
  • 区域设置 ID。
  • 项目网址。
  • 以表达式或文件形式的许可证。 该 licenseUrl 属性已弃用。 请改用 license nuspec 元数据元素
  • 一个说明文件。
  • 图标文件。 该 iconUrl 属性已弃用。 请改用 icon nuspec 元数据元素
  • 依赖项和引用的列表。
  • 有助于图库搜索的标记。

以下代码是典型的 (但虚构) .nuspec 文件,其中包含描述属性的注释:

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
    <metadata>
        <!-- An identifier that must be unique within the hosting gallery -->
        <id>Contoso.Utility.UsefulStuff</id>

        <!-- A package version number that's used when resolving dependencies -->
        <version>1.8.3</version>

        <!-- A comma-separated list of package authors that sometimes appears directly on the gallery -->
        <authors>Dejana Tesic, Rajeev Dey</authors>

        <!-- A project URL that provides a link for the gallery -->
        <projectUrl>http://github.com/contoso/UsefulStuff</projectUrl>

        <!-- License information that's displayed on the gallery -->
        <license type="expression">Apache-2.0</license>
        
        <!-- The location of a read-me file that's displayed in the Visual Studio Package Manager UI -->
        <readme>readme.md</readme>

        <!-- An icon that's used in the Visual Studio Package Manager UI -->
        <icon>icon.png</icon>

        <!-- 
            A property that when true, prompts the user to accept the license when
            installing the package
        -->
        <requireLicenseAcceptance>false</requireLicenseAcceptance>

        <!-- Detailed information about a particular release -->
        <releaseNotes>Bug fixes and performance improvements</releaseNotes>

        <!-- 
            A description that can be used in the Package Manager UI. The
            nuget.org gallery uses information you add in the portal. 
        -->
        <description>Core utility functions for web applications</description>

        <!-- Copyright information -->
        <copyright>Copyright ©2026 Contoso Corporation</copyright>

        <!-- Tags that appear in the gallery and can be used for tag searches -->
        <tags>web utility http json url parsing</tags>

        <!-- Dependencies that are automatically installed when the package is installed -->
        <dependencies>
            <dependency id="Newtonsoft.Json" version="9.0" />
        </dependencies>
    </metadata>

    <!-- A read-me Markdown file that's displayed in the Package Manager UI -->
    <files>
        <file src="readme.md" target="" />
        <file src="icon.png" target="" />
    </files>
</package>

有关声明依赖项和指定版本号的详细信息,请参阅 packages.config包版本控制。 还可以在dependency元素上使用includeexclude属性,来指定要在包中包含或排除的依赖项资产。 有关详细信息,请参阅 .nuspec Reference - Dependencies 元素

由于清单包含在从中创建的包中,因此可以通过检查现有包来查找示例。 良好的源是计算机上的 全局包 文件夹。 若要查找其位置,请使用以下命令:

nuget locals -list global-packages

了解 全局包 文件夹的位置后,请执行以下步骤来查找清单文件:

  1. 转到 全局包 文件夹。
  2. 在该文件夹中,转到任何包的子文件夹,然后转到该包的任何版本的子文件夹。
  3. 在版本子文件夹中,创建 .nupkg 文件的副本,并将副本的扩展名更改为 zip
  4. 打开 .zip 文件并检查其中 .nuspec 文件。

注释

从Visual Studio项目创建 .nuspec 文件时,清单中包含的一些标记会在生成包时替换为项目中的信息。 有关详细信息,请参阅 从 Visual Studio 项目创建 .nuspec 文件

创建 .nuspec 文件

创建完整清单通常以通过以下方法之一生成的基本 .nuspec 文件开始:

然后手动编辑文件,以便描述最终包中所需的确切内容。

重要

使用 nuget pack 命令创建包之前,您必须修改生成的 .nuspec 文件中包含的占位符。 如果 .nuspec 文件包含任何占位符,该命令将失败。

从基于约定的工作目录

由于 NuGet 包是使用 .nupkg 扩展名重命名的 ZIP 文件,因此通常最容易在本地文件系统上创建所需的文件夹结构,然后直接从该结构创建 .nuspec 文件。 然后,该 nuget pack 命令会自动添加该文件夹结构中的所有文件,但它排除以句点开头的任何文件夹,以便可以将专用文件保留在同一结构中。

此方法的优点是,无需在清单中指定要包含在包中的文件,如本部分后面所述。 相反,你可以让生成过程生成进入包的确切文件夹结构。 还可以轻松包含可能不属于项目的其他文件,否则:

  • 应注入目标项目的内容和源代码
  • PowerShell 脚本
  • 对项目中现有配置和源代码文件的转换

这些文件夹符合以下约定:

文件夹 内容 安装包时执行的操作
(根) 顶级文件夹、包清单,以及(可选的)README.md 文件和图标图像 此文件夹用作标准化子文件夹(如 libbuild)的起点。
lib/<tfm> 给定目标框架标识符(TFM)的程序集文件(.dll)、文档文件(.xml)和符号文件(.pdb) 程序集被添加为在编译时和运行时使用的引用。 .xml.pdb 文件将复制到项目文件夹中。 有关创建特定框架目标的子文件夹的信息,请参阅支持多个 .NET 版本
ref/<tfm> 给定 TFM 的程序集文件(.dll)和符号文件(.pdb 程序集仅在编译时作为引用添加。 项目 bin 文件夹中未复制任何内容。
运行时 特定于体系结构的程序集(.dll)、符号(.pdb)和本机资源(.pri)文件 程序集仅作为引用在运行时添加。 其他文件将复制到项目文件夹中。 在/ref/<tfm> 文件夹下,应始终有一个对应 (TFM) AnyCPU 特定程序集,以提供相应的编译时程序集。 请参阅 支持多个 .NET 版本
内容 任意文件 内容将复制到项目根目录。 将 内容 文件夹视为最终使用包的目标应用程序的根目录。 若要让包在应用程序的 /images 文件夹中添加图像,请将它放在包 的内容/图像 文件夹中。
构建 (3.x+) Microsoft Build引擎(MSBuild).targets.props文件 这些文件会自动插入到项目中。
buildMultiTargeting (4.0+) 用于跨框架目标的 MSBuild .targets.props 文件 这些文件会自动插入到项目中。
buildTransitive (5.0+) MSBuild .targets.props 文件,这些文件可传递流向任何使用的项目 这些文件会自动插入到项目中。 请参阅 功能 页。
工具 可从 程序包管理器 控制台访问的 PowerShell 脚本和程序 tools 文件夹仅添加到 程序包管理器 控制台的 PATH 环境变量中。 它 不会 添加到 MSBuild PATH 构建项目时使用的值中。

由于文件夹结构可以包含许多目标框架的程序集,因此在创建支持多个框架的包时,此方法是必需的。

准备好所需的文件夹结构后,在该文件夹中运行以下命令以创建 .nuspec 文件:

nuget spec

生成的 .nuspec 文件不包含对文件夹结构中的文件的显式引用。 NuGet 在创建包时自动包括所有文件。 你仍然需要编辑清单其他部分中的占位符值。

从程序集 DLL

在从程序集创建包的基本情况下,可以使用以下命令从程序集中的元数据生成 .nuspec 文件:

nuget spec <assembly-name>.dll

使用此表单将清单中的几个占位符替换为程序集中的特定值。 例如,该 <id> 属性设置为程序集名称,并 <version> 设置为程序集版本。 但是,清单中的其他属性在程序集中没有匹配的值。 运行命令后,这些属性仍然包含占位符。

从 Visual Studio 项目中

.csproj.vbproj 文件创建 .nuspec 文件很方便,因为项目中安装的其他包会自动引用为依赖项。 若要从项目文件创建清单,请在包含项目文件的文件夹中使用以下命令:

# Use in a folder that contains a project file, such as <project-name>.csproj or <project-name>.vbproj.
nuget spec

生成的 <project-name.nuspec> 文件包含标记,这些 令牌 会在打包时用项目中的相应值替换,其中包括对已安装的任何其他包的引用。

如果包依赖项要包含在 .nuspec 中,请改用 nuget pack。 然后从生成的 .nupkg 文件中获取 .nuspec 文件。 例如,使用以下命令:

# Use in a folder that contains a project file, such as <project-name>.csproj or <project-name>.vbproj.
nuget pack myproject.csproj

标记由 $ 项目属性两侧的符号分隔。 例如, <id> 以这种方式生成的清单中的值通常类似于以下行:

<id>$id$</id>

此令牌将在打包时被项目文件中的 AssemblyName 值替换。 有关将项目值精确映射到 .nuspec 文件令牌的信息,请参阅 替换令牌

使用令牌可避免在更新项目时需要手动更新关键值(例如 .nuspec 文件中的版本号)。 但你也可以将标记替换为文本值。

从Visual Studio项目中工作时,可以使用几种额外的打包选项,如本文后面所述的 运行 nuget pack 以生成 .nupkg 文件

解决方案级包

仅 NuGet 2.x。 NuGet 3.0+ 中不可用。

NuGet 2.x 支持解决方案级包的概念,该包为 程序包管理器 控制台(tools 文件夹的内容)安装工具或额外命令,但不向解决方案中的任何项目添加引用、内容或生成自定义项。 此类包在其直接 内容生成 文件夹中不包含文件,并且其依赖项中没有文件在其各自的 内容生成 文件夹中。

NuGet 跟踪 .nuget 文件夹中 packages.config 文件中已安装的解决方案级包,而不是项目的 packages.config 文件。

从具有默认值的新文件开始

以下命令创建包含占位符的默认清单,这有助于确保从正确的文件结构开始:

nuget spec [<package-name>]

如果省略 <package-name>,生成的文件名为 Package.nuspec。 如果您提供诸如 Contoso.Utility.UsefulStuff 这样的名称,那么文件名将为 Contoso.Utility.UsefulStuff.nuspec

生成的 .nuspec 文件包含类似于 projectUrl 的值的占位符。 在使用该文件创建最终的 .nupkg 文件之前,请将占位符替换为适当的值。

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

包标识符(<id> 元素)和版本号(<version> 元素)是清单中最重要的两个值,因为它们唯一标识包中包含的确切代码。

包标识符的最佳做法

  • 唯一性:标识符在承载包的库中必须是唯一的,例如 nuget.org。在决定标识符之前,请搜索适用的库,检查名称是否已在使用。 为了避免冲突,良好的模式是使用公司名称作为标识符的第一部分,例如 Contoso
  • 名称类似Namespace 的名称:遵循类似于.NET命名空间的模式,使用点表示法而不是连字符。 例如,使用 Contoso.Utility.UsefulStuff 而不是 Contoso-Utility-UsefulStuffContoso_Utility_UsefulStuff。 当包标识符与代码中使用的命名空间匹配时,使用者也会发现它很有用。
  • 示例包:如果生成示例代码包,演示如何使用另一个包,请附加 .Sample 为标识符的后缀,如中所示 Contoso.Utility.UsefulStuff.Sample。 此类型的示例包依赖于它演示如何使用的包。 创建示例包时,请使用前面所述的基于约定的工作目录方法。 在内容文件夹中,按照 < 中所示,在名为 \Samples\>identifier 的文件夹中排列示例代码。

包版本的最佳做法

  • 通常,将包的版本设置为与库匹配。 建议使用本指南,但并非严格要求。 将包限制为单个程序集时,这种做法非常简单,如前面在 决定要打包的程序集中所述。 通常,请记住,NuGet 本身在解析依赖项时处理包版本,而不是程序集版本。
  • 使用非标准版本方案时,请考虑 包版本控制中所述的 NuGet 版本控制规则。

有关有助于了解版本控制的其他资源,请参阅以下一系列简短博客文章:

添加自述文件和其他文件

若要直接指定要包含在包中的文件,请使用 <files>.nuspec 文件中的节点,该文件遵循<metadata>标记:

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
    <metadata>
        <!-- ... -->
    </metadata>
    <files>
        <!-- Add files from an arbitrary folder that's not necessarily in the project. -->
        <file src="..\..\SomeRoot\**\*.*" target="" />
    </files>
</package>

小窍门

使用基于约定的工作目录方法时,可以将 readme.md 文件放在包根目录和 内容 文件夹中的其他内容中。 清单中不需要 <file> 元素。

若要在包中包含自述文件,请使用 readme 元数据元素指定自述文件的目标路径。 此外,使用 file 元数据元素指定自述文件的源路径和目标文件夹。 有关详细信息,请参阅 readme

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
    <metadata>
        <!-- ... -->
        <readme>docs\readme.md</readme>
        <!-- ... -->
    </metadata>
    <files>
        <!-- Add a read-me file. -->
        <file src="..\readme.md" target="docs\" />
    </files>
</package>

Visual Studio在 程序包管理器 UI 中显示说明文件的内容。 例如,以下屏幕截图显示了 HtmlAgilityPack 包的自述文件:

Visual Studio 包管理器 UI 的屏幕截图,显示一个包详细信息窗格。README 选项卡描述了该包的 HTML 解析功能。

注释

如果在 <files> 文件中包括空节点,NuGet 将包含包中 lib 文件夹的内容,但不包含其他内容。

在软件包中包含 MSBuild 道具及任务目标

在某些情况下,可能需要将自定义生成目标或属性添加到使用包的项目,例如在生成过程中运行自定义工具或进程。 有关自定义生成目标和属性的详细信息,请参阅 包中的 MSBuild .props 和 .targets

在项目的build文件夹中创建 < 或 >package-id.props 文件,例如 Contoso.Utility.UsefulStuff.targets

然后在 .nuspec 文件中,在 <files> 节点中引用这些文件:

<?xml version="1.0"?>
<package >
    <metadata minClientVersion="2.5">
    <!-- ... -->
    </metadata>
    <files>
        <!-- In the package build folder, include everything that's in the local build folder. -->
        <file src="build\**" target="build" />

        <!-- Other files -->
        <!-- ... -->
    </files>
</package>

将包添加到项目时,NuGet 会自动包括这些属性和目标。

运行 nuget 包以生成 .nupkg 文件

使用程序集或基于约定的工作目录时,请运行nuget pack 并使用 .nuspec 文件来创建包。 在以下命令中,将 <project-name> 替换为你的项目名称:

nuget pack <project-name>.nuspec

使用Visual Studio项目时,请使用项目文件运行 nuget pack。 此命令会自动加载项目的 .nuspec 文件,并将其中的任何令牌替换为项目文件中的相应值:

nuget pack <project-name>.csproj

注释

对于令牌替换,必须直接使用项目文件,因为项目是令牌值的源。 当与 nuget pack 文件一起使用 .nuspec 时,令牌替换不会成功。

在所有情况下, nuget pack 都排除以句点开头的文件夹,例如 .git.hg

NuGet 指示 .nuspec 文件中是否有任何需要更正的错误,例如清单中需要更新的占位符值。

nuget pack成功后,你将拥有一个.nupkg文件,可以根据《发布 NuGet 包》中所述发布到合适的画廊。

小窍门

创建包后检查包的有用方法是在 包资源管理器 工具中打开它。 此工具提供包内容的图形视图及其清单。 还可以将生成的 .nupkg 文件重命名为 .zip 文件,并直接浏览其内容。

附加选项

可以使用各种命令行开关 nuget pack 来排除文件、替代清单中的版本号,以及更改输出文件夹以及其他功能。 有关完整列表,请参阅 pack 命令(NuGet CLI)。

以下选项是Visual Studio项目的一些常见选项:

  • 引用的项目:如果项目引用其他项目,则可以使用 -IncludeReferencedProjects 此选项将引用的项目添加为包的一部分或作为依赖项:

    nuget pack MyProject.csproj -IncludeReferencedProjects
    

    此包含过程是递归的。 例如,如果 MyProject.csproj 引用了项目 B 和 C,并且这些项目又引用了 D、E 和 F,那么 B、C、D、E 和 F 中的文件都将包含在包中。

    如果引用的项目包含其自身的 .nuspec 文件,NuGet 会将引用的项目添加为依赖项。 需要单独打包和发布该项目。

  • 生成配置:默认情况下,NuGet 使用项目文件中设置的默认生成配置,通常 Debug。 若要从其他生成配置中打包文件,例如 Release 的, 请使用 -properties 配置的选项:

    nuget pack MyProject.csproj -properties Configuration=Release
    
  • 符号:若要包括使使用者能够在调试器中单步执行包代码的符号,请使用 -Symbols-SymbolPackageFormat 选项。 请为-SymbolPackageFormat选项指定snupkg格式:

    nuget pack MyProject.csproj -symbols -SymbolPackageFormat snupkg
    

测试包安装

在发布包之前,通常需要测试将包安装到项目中的过程。 测试有助于确保所有必需的文件最终都位于项目中的正确位置。

可以使用标准 package 安装步骤在Visual Studio或命令行中手动测试安装。

对于自动测试,可以使用以下基本过程:

  1. .nupkg 文件复制到本地文件夹。
  2. 使用 nuget sources add -name <name> -source <path> 命令将文件夹添加到包源。 有关详细信息,请参阅源命令(NuGet CLI)。 只需在任何给定计算机上设置此本地源一次。
  3. 使用nuget install <package-ID> -source <name>从该源安装包。 在此命令中, <name> 应与在 nuget sources 命令中使用的源的名称匹配。 指定源会告知 NuGet 仅从该源安装该包。
  4. 检查文件系统以检查是否已正确安装文件。

创建包(即 .nupkg 文件)后,可以将其发布到您选择的画廊。 有关详细信息,请参阅 发布 NuGet 包

还可以扩展包的功能或支持其他方案。 如需了解更多信息,请参阅以下文章:

若要了解其他包类型,请参阅以下文章: