Создание пакета NuGet с помощью MSBuild

При создании пакета NuGet из кода вы формируете компонент, которым можно поделиться с любым количеством разработчиков для совместного использования. В этой статье описывается, как создать пакет с помощью MSBuild. MSBuild предустанавливается с каждой рабочей нагрузкой Visual Studio, содержащей NuGet. Кроме того, можно использовать MSBuild через dotnet CLI с помощью команды dotnet msbuild.

Для проектов .NET Core и .NET Standard с форматом в стиле пакета SDK и других проектов в таком стиле NuGet использует сведения в файле проекта напрямую для создания пакета. Для проекта в стиле, отличном от SDK, который использует <PackageReference>, NuGet также использует файл проекта для создания пакета.

Проекты в стиле SDK имеют функциональные возможности пакетирования по умолчанию. Для проектов PackageReference в стиле, отличном от SDK, необходимо добавить пакет NuGet.Build.Tasks.Pack в зависимости проекта. Подробные сведения о целевых объектах пакета MSBuild см. в разделе Пакет NuGet и восстановление в качестве целевых объектов MSBuild.

Команда, создающая пакет (msbuild -t:pack) функционально эквивалентна dotnet pack.

Важно!

Эта статья применяется к проектам в стиле SDK (обычно это проекты .NET Core и .NET Standard), а также к проектам в других стилях, использующим PackageReference.

Настройка свойств

Для создания пакета необходимы следующие свойства:

  • PackageId — идентификатор пакета, который должен быть уникальным в пределах коллекции, содержащей пакет. Если не задано, по умолчанию используется значение AssemblyName.
  • Version —определенный номер версии в формате основной_номер.дополнительный_номер.исправление[-суффикс] , где -суффикс указывает на предварительные версии. По умолчанию используется значение 1.0.0.
  • название пакета, которое должно отображаться на сайте размещения (например, nuget.org);
  • Authors — сведения об авторе и владельце. Если не задано, по умолчанию используется значение AssemblyName.
  • Company — название компании. Если не задано, по умолчанию используется значение AssemblyName.

Кроме того, при упаковке проектов, использующих PackageReference, в стиле, отличном от пакетов SDK, требуется следующее:

  • PackageOutputPath — выходная папка для пакета, созданного при вызове пакета.

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

Можно также задать дополнительные свойства, такие как Title, PackageDescription и PackageTags (см. подробнее об использовании целевых объектов пакета MSBuild, управлении ресурсами зависимостей и использовании свойств метаданных NuGet).

Примечание

Если пакет будет общедоступным, обратите особое внимание на свойство PackageTags, так как теги помогают найти ваш пакет и понять его назначение.

Подробные сведения об объявлении зависимостей и указании номеров версий см. в разделе Ссылки на пакеты в файлах проекта и Управление версиями пакетов. Доступ к ресурсам зависимостей в пакете можно также предоставлять напрямую с помощью атрибутов <IncludeAssets> и <ExcludeAssets>. См. подробнее об управлении ресурсами зависимостей.

Добавление необязательного поля описания

Необязательное описание пакета, отображаемое на странице NuGet.org пакета, получается из <description></description>, используемого в файле .csproj, или через $description в файле NUSPEC.

Пример поля Description показан в следующем XML-коде файла .csproj для пакета .NET:

<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://docs.microsoft.com/en-us/azure/storage/
      Microsoft Azure Storage REST API Reference - https://docs.microsoft.com/en-us/rest/api/storageservices/
      REST API Reference for Blob Service - https://docs.microsoft.com/en-us/rest/api/storageservices/blob-service-rest-api
    </Description>
  </PropertyGroup>
</Project>

Выбор уникального идентификатора пакета и номера версии

Идентификатор пакета и номер версии — два самых важных значения в проекте, так как они однозначно определяют код, содержащийся в пакете.

Рекомендации в отношении идентификатора пакета

  • Уникальность. Идентификатор должен быть уникальным в пределах nuget.org или другой коллекции, в которой размещается пакет. Прежде чем задавать идентификатор, проверьте, не используется ли оно уже в соответствующей коллекции. Во избежание конфликтов рекомендуется использовать в качестве первой части идентификатора название организации, например Contoso..
  • Имена в стиле пространств имен. Используйте шаблон, по которому строятся имена пространств имен в .NET, используя нотацию с точками, а не с дефисами. Например, используйте идентификатор Contoso.Utility.UsefulStuff вместо Contoso-Utility-UsefulStuff или Contoso_Utility_UsefulStuff. Пользователям также удобно, когда идентификатор пакета соответствует пространствам имен, используемым в коде.
  • Примеры пакетов. Если вы создаете пакет с примером кода, демонстрирующим использование другого пакета, добавьте к идентификатору суффикс .Sample, например Contoso.Utility.UsefulStuff.Sample. (У примера пакета, разумеется, существует зависимость от другого пакета.) При создании примера пакета используйте значение contentFiles в <IncludeAssets>. В папке content разместите код образца в папке с именем \Samples\<identifier>, например \Samples\Contoso.Utility.UsefulStuff.Sample.

Рекомендации в отношении версии пакета

  • Как правило, версия пакета должна соответствовать версии проекта (или сборки), хотя это не строгое требование. Но это упрощает работу, когда вы используете для пакета одну сборку. В целом помните, что при разрешении зависимостей диспетчер NuGet ориентируется на версии пакетов, а не на версии сборок.
  • При применении нестандартной схемы версий обязательно учитывайте правила управления версиями в NuGet, которые изложены в разделе Управление версиями пакета. NuGet в основном поддерживает SemVer 2.

См. подробнее о разрешении зависимостей с помощью PackageReference. Более старые сведения, которые помогут вам узнать об управлении версиями, см. в этой серии записей блога.

Добавление пакета NuGet.Build.Tasks.Pack

Если вы используете MSBuild с проектом в стиле, отличном от SDK, и PackageReference, добавьте пакет NuGet.Build.Tasks.Pack в проект.

  1. Откройте файл проекта и добавьте следующее после элемента <PropertyGroup>:

    <ItemGroup>
      <!-- ... -->
      <PackageReference Include="NuGet.Build.Tasks.Pack" Version="5.2.0"/>
      <!-- ... -->
    </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 или в командной строке, выполнив стандартную процедуру установки пакета.

Важно!

Пакеты не изменяются. Если вы устраните проблему, измените содержимое пакета и снова выполните упаковку, при повторном тестировании вы все равно будете использовать старую версию пакета до тех пор, пока не будет очищена папка глобальных пакетов. Это особенно важно при тестировании пакетов, которые не используют уникальную метку предварительной версии при каждой сборке.

Next Steps

Создав пакет, то есть файл .nupkg, вы можете опубликовать его в любой коллекции на ваш выбор, как описано в разделе Публикация пакета.

Вы также можете расширить возможности пакета или обеспечить поддержку других сценариев, как описано в следующих разделах:

Наконец, существуют дополнительные типы пакетов, о которых нужно знать: