使用 nuget.exe CLI 创建包

无论您的软件包执行什么功能或包含什么代码,您都可以使用 CLI 工具nuget.exedotnet.exe之一将该功能打包成组件,以便与其他开发人员共享和使用。 若要安装 NuGet CLI 工具,请参阅 安装 NuGet 客户端工具。 请注意,Visual Studio 不会自动包含 CLI 工具。

从技术上讲,NuGet 包只是使用扩展名重命名 .nupkg 的 ZIP 文件,其内容与某些约定匹配。 本主题介绍创建满足这些约定的包的详细过程。

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

重要

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

确定要打包的程序集

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

  • 一般情况下,最好为每个 NuGet 包创建一个程序集,前提是每个程序集独立有用。 例如,如果你有一个Utilities.dll依赖于Parser.dll,而Parser.dll本身很有用,那么应该为每个单独创建一个包。 这样,开发人员就可以独立于Utilities.dll使用Parser.dll

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

  • 同样,如果 Utilities.dll 依赖于 Utilities.resources.dll后者,后者本身又没有用处,那么请将两者放在同一个包中。

事实上,资源是一种特殊情况。 将包安装到项目中时,NuGet 会自动向包的 DLL 添加程序集引用, 不包括 那些被命名 .resources.dll 的程序集,因为它们假定是本地化附属程序集(请参阅 “创建本地化包”。 因此,请避免对包含基本包代码的文件使用 .resources.dll

如果您的库包含 COM 互操作程序集,请按照 使用 COM 互操作程序集创建包中的其他准则进行操作。

.nuspec 文件的角色和结构

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

清单:

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

必需属性:

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

常见的可选属性:

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

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

        <!-- Package version number that is used when resolving dependencies -->
        <version>1.8.3</version>

        <!-- Authors contain text that appears directly on the gallery -->
        <authors>Dejana Tesic, Rajeev Dey</authors>

        <!-- 
            Owners are typically nuget.org identities that allow gallery
            users to easily find other packages by the same owners.  
        -->
        <owners>dejanatc, rjdey</owners>
        
         <!-- Project URL provides a link for the gallery -->
        <projectUrl>http://github.com/contoso/UsefulStuff</projectUrl>

         <!-- License information is displayed on the gallery -->
        <license type="expression">Apache-2.0</license>
        

        <!-- Icon is used in Visual Studio's package manager UI -->
        <icon>icon.png</icon>

        <!-- 
            If true, this value prompts the user to accept the license when
            installing the package. 
        -->
        <requireLicenseAcceptance>false</requireLicenseAcceptance>

        <!-- Any details about this particular release -->
        <releaseNotes>Bug fixes and performance improvements</releaseNotes>

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

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

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

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

    <!-- A readme.txt to display when the package is installed -->
    <files>
        <file src="readme.txt" target="" />
        <file src="icon.png" target="" />
    </files>
</package>

有关声明依赖项和指定版本号的详细信息,请参阅 packages.config包版本控制。 还可以通过在dependency元素上使用includeexclude属性,直接在包中显示依赖项中的资源。 请参阅 .nuspec 参考 - 依赖项

由于清单包含在从中创建的包中,因此可以通过检查现有包来查找任意数量的附加示例。 良好的源是计算机上的 全局包 文件夹,该文件夹的位置由以下命令返回:

nuget locals -list global-packages

进入任何 package\version 文件夹,将 .nupkg 文件复制到文件 .zip ,然后打开该文件 .zip 并检查 .nuspec 其中的文件。

注释

从 Visual Studio 项目创建 .nuspec 时,清单文件包含在生成包时替换为项目中信息的令牌。 请参阅 从 Visual Studio 项目创建 .nuspec

创建 .nuspec 文件

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

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

重要

生成的.nuspec文件包含占位符nuget pack,需要在使用命令创建包之前进行修改。 如果该命令包含任何占位符,该 .nuspec 命令将失败。

从基于约定的工作目录

由于 NuGet 包只是使用扩展名重命名 .nupkg 的 ZIP 文件,因此通常最容易在本地文件系统上创建所需的文件夹结构,然后直接从该结构创建 .nuspec 文件。 然后,该 nuget pack 命令会自动添加该文件夹结构中的所有文件(不包括任何以 .开头的文件夹,允许将专用文件保存在同一结构中)。

此方法的优点是,无需在清单中指定要包含在包中的文件(如本主题稍后所述)。 只需让构建过程生成进入包的准确文件夹结构,并且可以轻松包含其他可能不属于项目的文件。

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

文件夹约定如下所示:

文件夹 Description 安装包时执行的操作
(root) readme.txt 的位置 安装包时,Visual Studio 会在包根目录中显示 readme.txt 文件。
lib/{tfm} 给定目标框架标识符(TFM)的程序集(.dll)、文档(.xml)和符号(.pdb)文件 程序集被添加为编译和运行时的引用,并且 .xml.pdb 被复制到项目文件夹中。 请参阅 支持多个目标框架,以了解如何创建特定框架的子文件夹。
ref/{tfm} 给定目标框架标识符(TFM)的程序集(.dll)和符号文件(.pdb 程序集仅在编译期间作为引用添加,因此不会将任何内容复制到项目的 bin 目录中。
运行时 特定于体系结构的程序集 (.dll)、符号 (.pdb) 和本机资源 (.pri) 文件 程序集仅作为运行时的引用添加;其他文件将复制到项目文件夹中。 应始终在/ref/{tfm}文件夹下有一个相应的AnyCPU(TFM)特定程序集,以提供相应的编译时程序集。 请参阅 支持多个目标框架
内容 任意文件 内容将复制到项目根目录。 将 内容 文件夹视为最终使用包的目标应用程序的根目录。 若要让包在应用程序的 /images 文件夹中添加图像,请将它放在包 的内容/图像 文件夹中。
内部版本 (3.x+) MSBuild .targets.props 文件 自动被插入到项目中。
buildMultiTargeting (4.0+) 用于跨框架目标的 MSBuild .targets.props 文件 自动插入项目中。
buildTransitive (5.0+) MSBuild .targets.props 可传递流向任何使用的项目的文件。 请参阅 功能 页。 自动插入到项目中。
tools 可从包管理器控制台访问的 Powershell 脚本和程序 tools文件夹仅被添加到PATH包管理器控制台的环境变量中(具体来说,而不是在项目构建时设置的PATH MSBuild 版本中)。

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

在任何情况下,一旦准备好所需的文件夹结构,请在该文件夹中运行以下命令以创建 .nuspec 文件:

nuget spec

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

从程序集 DLL

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

nuget spec <assembly-name>.dll

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

从 Visual Studio 项目

.nuspec 是从某个 .csproj.vbproj 文件创建的,这很方便,因为已安装到这些项目中的其他包会自动被引用为依赖项。 只需在项目文件所在的文件夹中使用以下命令:

# Use in a folder containing a project file <project-name>.csproj or <project-name>.vbproj
nuget spec

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

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

# Use in a folder containing a project file <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 )安装工具或其他命令,但不向解决方案中的任何项目添加引用、内容或生成自定义项。 此类包在其直接libcontentbuild文件夹中不包含任何文件,并且其依赖项中没有其各自的lib文件或contentbuild文件夹。

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

具有默认值的新文件

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

nuget spec [<package-name>]

如果省略 <包名称>,则生成的文件为 Package.nuspec. 如果您提供名称,例如Contoso.Utility.UsefulStuff,文件将是Contoso.Utility.UsefulStuff.nuspec

生成的 .nuspec 包含像 projectUrl 这样的值的占位符。 在使用该文件创建最终 .nupkg 文件之前,请务必编辑该文件。

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

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

包标识符的最佳做法:

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

关于软件包版本的最佳实践:

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

以下一系列简短博客文章也有助于了解版本控制:

添加说明文件和其他文件

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

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
    <metadata>
    <!-- ... -->
    </metadata>
    <files>
        <!-- Add a readme -->
        <file src="readme.txt" target="" />

        <!-- Add files from an arbitrary folder that's not necessarily in the project -->
        <file src="..\..\SomeRoot\**\*.*" target="" />
    </files>
</package>

小窍门

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

在包根目录中包括一个名为 readme.txt 的文件时,Visual Studio 会在直接安装包后立即将该文件的内容显示为纯文本。 (对于作为依赖项安装的包,不显示自述文件)。 例如,HtmlAgilityPack 包的自述文件显示如下:

安装后 NuGet 包的自述文件显示

注释

如果在 .nuspec 文件中包含一个空的 <files> 节点,NuGet 就不会在包中包含其他内容,仅包含 lib 文件夹中的内容。

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

在某些情况下,你可能希望在使用包的项目中添加自定义生成目标或属性,例如在生成过程中运行自定义工具或进程。 可以在 NuGet 包中了解有关 MSBuild 属性和目标的详细信息

在项目的生成文件夹中创建 <package_id>.targets<package_id>.props (例如 Contoso.Utility.UsefulStuff.targets)。

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

<?xml version="1.0"?>
<package >
    <metadata minClientVersion="2.5">
    <!-- ... -->
    </metadata>
    <files>
        <!-- Include everything in \build -->
        <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文件,可以将其发布到适合的画廊,详见发布一个包

小窍门

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

附加选项

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

以下选项是 Visual Studio 项目通用的一些选项:

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

    nuget pack MyProject.csproj -IncludeReferencedProjects
    

    此包含过程是递归的,因此,如果 MyProject.csproj 引用项目 B 和 C,并且这些项目引用 D、E 和 F,则包中包含 B、C、D、E 和 F 中的文件。

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

  • 生成配置:默认情况下,NuGet 使用项目文件中的默认生成配置集,通常 为 Debug。 若要从其他构建配置(如发布)打包文件,请使用带有配置的-properties选项:

    nuget pack MyProject.csproj -properties Configuration=Release
    
  • 符号:若要包含允许使用者在调试器中单步执行包代码的符号,请使用 -Symbols 以下选项:

    nuget pack MyProject.csproj -symbols
    

测试包安装

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

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

对于自动测试,基本过程如下所示:

  1. .nupkg 文件复制到本地文件夹。
  2. 使用 nuget sources add -name <name> -source <path> 命令将文件夹添加到包源(请参阅 nuget 源)。 请注意,在任何给定计算机上只需设置此本地源一次。
  3. 使用nuget install <packageID> -source <name>从该来源安装包,其中<name>与提供给nuget sources的来源名称匹配。 指定源可确保只能从该指定源安装包。
  4. 检查文件系统以检查是否已正确安装文件。

后续步骤

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

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

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