PackageReference
в файлах проектов
Ссылки на пакеты, использующие элементы MSBuild <PackageReference>
, указывают зависимости пакетов NuGet непосредственно в файлах проекта, а не в отдельных файлах packages.config
. Использование PackageReference не влияет на другие аспекты NuGet. Например, параметры в файлах NuGet.Config
(включая источники пакетов) по-прежнему применяются, как описано в разделе Распространенные конфигурации NuGet.
PackageReference также позволяет использовать условия MSBuild для выбора ссылок на пакеты в соответствии с целевой платформой и другими признаками. Он также обеспечивает детальный контроль над зависимостями и потоком содержимого. (Дополнительные сведения см. в разделе Объекты pack и restore NuGet в качестве целевых объектов MSBuild.)
Поддержка типов проектов
По умолчанию PackageReference используется для проектов .NET Core, проектов .NET Standard и проектов универсальной платформы Windows, предназначенных для сборки 15063 системы Windows 10 (Creators Update), за исключением проектов C++ UWP. Проекты .NET Framework поддерживают PackageReference, но сейчас по умолчанию используют packages.config
. Чтобы использовать PackageReference, перенесите зависимости из packages.config
в файл проекта, а затем удалите packages.config.
Приложения ASP.NET, предназначенные для полной версии .NET Framework, включают только ограниченную поддержку для PackageReference. Типы проектов C++и JavaScript не поддерживаются.
Добавление PackageReference
Добавьте зависимость в файл проекта, используя следующий синтаксис:
<ItemGroup>
<!-- ... -->
<PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0" />
<!-- ... -->
</ItemGroup>
Управление версией зависимости
При указании версии пакета действует то же соглашение, что и при использовании файла packages.config
.
<ItemGroup>
<!-- ... -->
<PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0" />
<!-- ... -->
</ItemGroup>
В приведенном выше примере значение 3.6.0 означает версию 3.6.0 или любую более позднюю версию, причем предпочтение отдается самой ранней версии, как описано в разделе Управление версиями пакета.
Использование PackageReference для проекта без зависимостей пакета
Дополнительно: если в проекте нет установленных пакетов (нет объектов PackageReference в файле, а также файла packages.config), но вы хотите восстанавливать проект в стиле PackageReference, можно задать для свойства RestoreProjectStyle проекта значение PackageReference в файле проекта.
<PropertyGroup>
<!--- ... -->
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
<!--- ... -->
</PropertyGroup>
Это может быть удобно при ссылке на проекты в стиле PackageReference (существующие CSPROJ- или SDK-проекты). Это позволит вашему проекту транзитивно ссылаться на пакеты, на которые ссылаются эти проекты.
PackageReference и источники
В проектах PackageReference временные версии зависимостей разрешаются во время восстановления. Поэтому в них все источники должны быть доступны для всех операций восстановления.
Гибкие версии
Гибкие версии можно использовать с PackageReference
:
<ItemGroup>
<!-- ... -->
<PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.*" />
<PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0-beta.*" />
<!-- ... -->
</ItemGroup>
Управление ресурсами зависимости
Зависимость может применяться исключительно для удобства разработки. В этом случае доступ к ней не нужно предоставлять проектам, использующим пакет. Для управления таким поведением могут служить метаданные PrivateAssets
.
<ItemGroup>
<!-- ... -->
<PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<!-- ... -->
</ItemGroup>
Ниже перечислены теги метаданных, управляющие ресурсами зависимостей.
Тег | Description | Значение по умолчанию |
---|---|---|
IncludeAssets | Эти ресурсы будут использоваться. | all |
ExcludeAssets | Эти ресурсы не будут использоваться. | ничего |
PrivateAssets | Эти ресурсы будут использоваться, но не будут передаваться в родительский проект. | contentfiles;analyzers;build |
Ниже приводятся допустимые значения этих тегов. Несколько значений должны разделяться точкой с запятой. Это не относится к значениям all
и none
, которые должны использоваться отдельно.
значение | Описание |
---|---|
compile | Содержимое папки lib ; управляет возможностью компиляции проекта с использованием сборок в этой папке |
среда выполнения | Содержимое папки lib и runtimes ; управляет возможностью копирования этих сборок в выходной каталог сборки |
contentFiles | Содержимое папки contentfiles |
сборка | .props и .targets в папке build |
buildMultitargeting | Файлы .props и .targets (4.0) в папке buildMultitargeting для кроссплатформенного определения. |
buildTransitive | Файлы .props и .targets (5.0+) в папке buildTransitive для ресурсов, которые можно транзитивно передавать в любой соответствующий проект. См. об этой функции. |
analyzers | Анализаторы .NET |
платформы | Содержимое папки native |
ничего | Никакие из перечисленных выше ресурсов не используются. |
all | Используются все перечисленные выше ресурсы (кроме none ). |
<ItemGroup>
<!-- ... -->
<!-- Everything except the content files will be consumed by the project -->
<!-- Everything except content files and analyzers will flow to the parent project-->
<PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0">
<IncludeAssets>all</IncludeAssets> <!-- Default is `all`, can be omitted-->
<ExcludeAssets>contentFiles</ExcludeAssets>
<PrivateAssets>contentFiles;analyzers</PrivateAssets>
</PackageReference>
<!-- ... -->
<!-- Everything except the compile will be consumed by the project -->
<!-- Everything except contentFiles will flow to the parent project-->
<PackageReference Include="Contoso.Utility.SomeOtherUsefulStuff" Version="3.6.0">
<ExcludeAssets>compile</ExcludeAssets>
<PrivateAssets>contentFiles</PrivateAssets>
</PackageReference>
<!-- ... -->
</ItemGroup>
Обратите внимание: так как папка build
не включена в PrivateAssets
, цели и свойства будут передаваться в родительский проект. Предположим, что приведенная выше ссылка используется в проекте, в рамках которого выполняется сборка пакета NuGet с именем AppLogger. Пакет AppLogger может использовать цели и свойства из Contoso.Utility.UsefulStuff
, так же как и проекты, использующие AppLogger.
Примечание.
Когда для developmentDependency
в файле .nuspec
задано значение true
, это указывает на то, что пакет помечен как зависимость только для разработки, что позволяет запретить его включение в качестве зависимости в другие пакеты. При использовании PackageReference (NuGet 4.8+) этот флажок также указывает на исключение ресурсов времени компиляции из компиляции. Дополнительные сведения см. в статье DevelopmentDependency support for PackageReference (Поддержка DevelopmentDependency для PackageReference).
Добавление условия PackageReference
С помощью условий можно управлять тем, когда следует включать пакет. В условиях можно использовать любые переменные MSBuild или переменные, определенные в файлах целей или свойств. Однако в настоящее время поддерживается только переменная TargetFramework
.
Например, предположим, что целевыми платформами являются netstandard1.4
и net452
, но зависимость применима только для net452
. В этом случае в проект netstandard1.4
, который использует пакет, не следует добавлять эту ненужную зависимость. В этом случае в узле PackageReference
можно указать следующее условие:
<ItemGroup>
<!-- ... -->
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" Condition="'$(TargetFramework)' == 'net452'" />
<!-- ... -->
</ItemGroup>
При сборке пакета с использованием этого проекта файл Newtonsoft.Json будет отображаться как включенный только в виде зависимости для целевого объекта net452
:
Условия можно также применять на уровне ItemGroup
. В этом случае они применяются ко всем дочерним элементам PackageReference
.
<ItemGroup Condition = "'$(TargetFramework)' == 'net452'">
<!-- ... -->
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0" />
<!-- ... -->
</ItemGroup>
GeneratePathProperty
Эта функция доступна в NuGet 5.0 или более поздней версии и в Visual Studio 2019 16.0 или более поздней версии.
Иногда требуется ссылаться на файлы в пакете из целевого объекта MSBuild.
В проектах на основе packages.config
пакеты устанавливаются в папку относительно файла проекта. Однако в PackageReference пакеты используются из папки global-packages, которая может отличаться на разных компьютерах.
Чтобы устранить эту проблему, NuGet предоставляет свойство, указывающее на расположение, из которого будет использоваться пакет.
Пример:
<ItemGroup>
<PackageReference Include="Some.Package" Version="1.0.0" GeneratePathProperty="true" />
</ItemGroup>
<Target Name="TakeAction" AfterTargets="Build">
<Exec Command="$(PkgSome_Package)\something.exe" />
</Target>
Кроме того, NuGet автоматически создаст свойства для пакетов, содержащих папку tools.
<ItemGroup>
<PackageReference Include="Package.With.Tools" Version="1.0.0" />
</ItemGroup>
<Target Name="TakeAction" AfterTargets="Build">
<Exec Command="$(PkgPackage_With_Tools)\tools\tool.exe" />
</Target>
Свойства MSBuild и удостоверения пакетов не имеют одинаковых ограничений, поэтому удостоверение пакета необходимо изменить на понятное имя MSBuild с префиксом в виде слова Pkg
.
Чтобы проверить точное имя создаваемого свойства, изучите созданный файл nuget.g.props.
Псевдонимы PackageReference
В некоторых редких случаях разные пакеты могут содержать классы в одном и том же пространстве имен. Начиная с NuGet версии 5.7 и обновления 7 для Visual Studio 2019 PackageReference поддерживает Aliases
, аналогично ProjectReference.
По умолчанию никакие псевдонимы не предоставляются. Если псевдоним указан, ссылки на все сборки из аннотированного пакета должны указываться с псевдонимом.
Пример использования см. в разделе NuGet\Примеры
В файле проекта псевдонимы указываются следующим образом:
<ItemGroup>
<PackageReference Include="NuGet.Versioning" Version="5.8.0" Aliases="ExampleAlias" />
</ItemGroup>
В коде это используется следующим образом:
extern alias ExampleAlias;
namespace PackageReferenceAliasesExample
{
...
{
var version = ExampleAlias.NuGet.Versioning.NuGetVersion.Parse("5.0.0");
Console.WriteLine($"Version : {version}");
}
...
}
Предупреждения и ошибки NuGet
Эта функция доступна в NuGet 4.3 или более поздней версии и в Visual Studio 2017 15.3 или более поздней версии.
Для многих сценариев упаковки и восстановления все предупреждения и ошибки NuGet кодируются и начинаются с NU****
. Все предупреждения и ошибки NuGet перечислены в справочной документации.
NuGet следит за следующими свойствами предупреждения:
TreatWarningsAsErrors
— обработка всех предупреждений как ошибок.WarningsAsErrors
— обработка указанных предупреждений как ошибок.NoWarn
— скрытие определенных предупреждений в масштабе проекта или пакета.
Примеры:
<PropertyGroup>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
...
<PropertyGroup>
<WarningsAsErrors>$(WarningsAsErrors);NU1603;NU1605</WarningsAsErrors>
</PropertyGroup>
...
<PropertyGroup>
<NoWarn>$(NoWarn);NU5124</NoWarn>
</PropertyGroup>
...
<ItemGroup>
<PackageReference Include="Contoso.Package" Version="1.0.0" NoWarn="NU1605" />
</ItemGroup>
Подавление предупреждений NuGet
Хотя рекомендуется разрешать все предупреждения NuGet во время выполнения операций упаковки и восстановления, в некоторых ситуациях их подавление гарантируется. Чтобы подавить предупреждение в масштабе проекта, рекомендуется сделать следующее:
<PropertyGroup>
<PackageVersion>5.0.0</PackageVersion>
<NoWarn>$(NoWarn);NU5104</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Contoso.Package" Version="1.0.0-beta.1"/>
</ItemGroup>
Иногда предупреждения применяются только к определенному пакету в графе. Мы можем выборочно подавить такое предупреждение, добавив NoWarn
к элементу PackageReference.
<PropertyGroup>
<PackageVersion>5.0.0</PackageVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Contoso.Package" Version="1.0.0-beta.1" NoWarn="NU1603" />
</ItemGroup>
Подавление предупреждений пакета NuGet в Visual Studio
В Visual Studio можно также подавить предупреждения в интегрированной среде разработки.
Блокировка зависимостей
Эта функция доступна в NuGet 4.9 или более поздней версии и в Visual Studio 2017 15.9 или более поздней версии.
Входные данные для восстановления в NuGet — это набор элементов PackageReference
из файла проекта (зависимости верхнего уровня или прямые зависимости). Выходные данные — это полный набор всех зависимостей пакета, включая транзитивные зависимости. NuGet всегда пытается создать одну и ту же полную систему зависимостей пакета, если входной список PackageReference не был изменен. Но в некоторых случаях это нельзя осуществить. Например:
При использовании гибких версий, таких как
<PackageReference Include="My.Sample.Lib" Version="4.*"/>
. При каждом восстановлении пакетов предполагается перейти к последней версии. Но иногда пользователям требуется, чтобы граф был закреплен за определенной последней версией, а переход к более поздней версии, если она доступна, происходил при явном указании.Опубликована более новая версия пакета PackageReference, которая соответствует требованиям к версии. Пример:
День 1. Предположим, вы указали
<PackageReference Include="My.Sample.Lib" Version="4.0.0"/>
, но в репозиториях NuGet были доступны версии 4.1.0, 4.2.0 и 4.3.0. В таком случае NuGet будет разрешен до версии 4.1.0 (ближайшей минимальной версии).День 2. Публикуется версия 4.0.0. NuGet найдет точное соответствие и приступит разрешению до версии 4.0.0.
Указанная версия пакета будет удалена из репозитория. Хотя на сайте nuget.org нельзя удалять пакеты, не все репозитории пакетов имеют такие ограничения. В результате этого в NuGet выполняется поиск наиболее соответствующей версии, если не удается разрешить удаленную версию.
Включение функции файла блокировки
Чтобы сохранить всю систему зависимостей пакета, можно воспользоваться функцией файла блокировки. Для этого задайте свойство MSBuild RestorePackagesWithLockFile
для проекта:
<PropertyGroup>
<!--- ... -->
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<!--- ... -->
</PropertyGroup>
Если это свойство задано, при восстановлении в NuGet будет создан файл блокировки — packages.lock.json
. Он содержит список всех зависимостей пакета и находится в корневом каталоге проекта.
Примечание.
Когда в корневом каталоге проекта появится файл блокировки packages.lock.json
, он будет использоваться при каждом восстановлении, даже если свойство RestorePackagesWithLockFile
не задано. Еще один способ воспользоваться этой функцией — создать пустой файл packages.lock.json
в корневом каталоге проекта.
Поведение restore
при использовании файла блокировки
Если для проекта создан файл блокировки, NuGet использует этот файл для запуска restore
. NuGet быстро проверяет наличие изменений в зависимостях пакетов, как указано в файле проекта (или в зависимых файлах проекта). Если такие изменения не обнаружены, NuGet просто восстанавливает пакеты, указанные в файле блокировки. Повторная проверка зависимостей пакета не выполняется.
Если диспетчер NuGet обнаруживает изменения в определенных зависимостях, указанных в файлах проекта, NuGet повторно проверяет граф пакета и обновляет файл блокировки в соответствии с новой схемой пакета для проекта.
В сценариях CI/CD и других сценариях, не требующих изменения зависимостей пакета во время выполнения, это можно сделать, задав для lockedmode
значение true
:
Для dotnet.exe выполните следующую команду:
> dotnet.exe restore --locked-mode
Для msbuild.exe выполните такую команду:
> msbuild.exe -t:restore -p:RestoreLockedMode=true
Это условное свойство MSBuild также можно задать в файле проекта:
<PropertyGroup>
<!--- ... -->
<RestoreLockedMode>true</RestoreLockedMode>
<!--- ... -->
</PropertyGroup>
Если для режима блокировки задано значение true
, восстановятся именно те пакеты, которые перечислены в файле блокировки. Либо восстановление завершится ошибкой, если вы обновили определенные зависимости пакетов для проекта после создания файла блокировки.
Добавление файла блокировки в исходный репозиторий
Если при создании приложения вы обнаружили, что исполняемый файл и рассматриваемый проект находятся в начале цепочки зависимостей, верните файл блокировки в репозиторий исходного кода. Так диспетчер NuGet сможет использовать его во время восстановления.
Но если это проект библиотеки, который не следует отправлять, или проект общего кода, от которого зависят другие проекты, не нужно возвращать файл блокировки в исходный код. Сохранение файла блокировки не причинит вреда. Но заблокированные зависимости пакетов, перечисленные в файле блокировки, нельзя использовать для проекта общего кода во время восстановления или сборки проекта, который зависит от этого проекта общего кода.
Например,
ProjectA
|------> PackageX 2.0.0
|------> ProjectB
|------>PackageX 1.0.0
Если ProjectA
зависит от PackageX
версии 2.0.0
и ссылается на проект ProjectB
, который зависит от PackageX
версии 1.0.0
, файл блокировки для ProjectB
будет содержать зависимость от PackageX
версии 1.0.0
. Но при создании проекта ProjectA
его файл блокировки будет содержать зависимость от PackageX
версии 2.0.0
, а не 1.0.0
, как указано в файле блокировки для ProjectB
. Таким образом, файл блокировки проекта общего кода играет незначительную роль для разрешенных пакетов, от которых зависят проекты.
Расширяемость файла блокировки
Вы можете управлять различным поведением восстановления с использованием файла блокировки, как описано ниже.
Вариант NuGet.exe | Вариант dotnet | Вариант, аналогичный использованию MSBuild | Description |
---|---|---|---|
-UseLockFile |
--use-lock-file |
RestorePackagesWithLockFile | Разрешение использовать файл блокировки. |
-LockedMode |
--locked-mode |
RestoreLockedMode | Включение режима блокировки для восстановления. Это полезно в сценариях CI/CD, когда нужно реализовать воспроизводимые сборки. |
-ForceEvaluate |
--force-evaluate |
RestoreForceEvaluate | Этот параметр удобно использовать с пакетами с гибкими версиями, определенными в проекте. По умолчанию в NuGet версия пакета не обновляется автоматически после каждого восстановления, если вы не запустили восстановление с этим параметром. |
-LockFilePath |
--lock-file-path |
NuGetLockFilePath | Определение размещения пользовательского файла блокировки для проекта. По умолчанию в NuGet файл packages.lock.json хранится в корневом каталоге. Если в одном каталоге хранится несколько проектов, NuGet поддерживает использование файла блокировки packages.<project_name>.lock.json для определенного проекта. |
Сопоставитель зависимостей NuGet
Сопоставитель зависимостей NuGet следует 4 правилам, как описано в документе разрешения зависимостей.
Чтобы повысить производительность и масштабируемость операции восстановления, алгоритм восстановления был перезаписан в выпуске 6.12.
По состоянию на выпуск 6.12 новый алгоритм восстановления включен по умолчанию для всех проектов PackageReference.
Хотя новый алгоритм восстановления функционально эквивалентен предыдущему, как и в любом программном обеспечении, возможны ошибки.
Чтобы вернуться к предыдущей реализации, задайте для свойства RestoreUseLegacyDependencyResolver
MSBuild значение true
.
Если вы столкнулись с ошибками восстановления в версии 6.12, .NET 9 или 17.12, которые не воспроизводились в более ранних версиях, отправьте сообщение о проблеме на сайте GitHub. Любые различия между старыми и новыми алгоритмами могут иметь различные последствия, например во время компиляции или во время выполнения. Есть также вероятность того, что изменения не приводят к сбоям, но восстановление различных версий пакетов. Если вы считаете, что вы можете повлиять на любые изменения, ниже приведены шаги, которые можно предпринять, чтобы проверить, являются ли изменения в алгоритме восстановления NuGet первопричиной.
Восстановление записывает результаты в MSBuildProjectExtensionsPath
каталог, который можно сравнить с новыми и старыми алгоритмами для поиска различий.
Обычно это obj
папка сборки.
Вы можете использовать msbuild.exe
или dotnet.exe
выполнить следующие действия.
- Удалите папку
obj
для проекта. - Выполнить
msbuild -t:restore
- Сохраните содержимое
obj
расположения, указывающее, что этоnew
поведение. - Выполнить
msbuild -t:restore -p:RestoreUseLegacyDependencyResolver="true"
- Сохраните содержимое
obj
расположения, указывающее, что этоlegacy
поведение. - Сравните файлы в двух каталогах, особенно project.assets.json. Средства, которые могут выделить различия, особенно полезны для этого (например, Visual Studio Code, открытие обоих файлов и использование правой кнопкой мыши "Выбрать для сравнения" и "сравнить с выбранным")
При выполнении приведенного выше метода должно быть ровно 1 разность между файлами project.assets.json
:
"projectStyle": "PackageReference",
+ "restoreUseLegacyDependencyResolver": true,
"fallbackFolders": [
Если есть дополнительные различия, отправьте проблему на GitHub со всеми сведениями.
AssetTargetFallback
Свойство AssetTargetFallback
позволяет указать дополнительные совместимые версии платформы для проектов, на которые ссылается ваш проект, и пакеты NuGet, используемые в проекте.
Если вы указали зависимость пакета с помощью PackageReference
, но в этом пакете нет ресурсов, совместимых с целевой платформой вашего проекта, тогда пригодится свойство AssetTargetFallback
. Совместимость пакета, на который указывает ссылка, повторно проверяется с помощью каждой целевой платформы, указанной в свойстве AssetTargetFallback
.
При обращении к project
или package
через AssetTargetFallback
вызывается предупреждение NU1701.
Примеры того, как AssetTargetFallback
влияет на совместимость, приводятся в следующей таблице.
Платформа проекта | AssetTargetFallback | Платформы пакета | Результат |
---|---|---|---|
.NET Framework 4.7.2. | .NET Standard 2.0 | .NET Standard 2.0 | |
.NET Core App 3.1 | .NET Standard 2.0, .NET Framework 4.7.2 | .NET Standard 2.0 | |
.NET Core App 3.1 | .NET Framework 4.7.2. | Несовместимо, сбой для NU1202 |
|
.NET Core App 3.1 | net472;net471 | .NET Framework 4.7.2. | .NET Framework 4.7.2 с NU1701 |
Чтобы указать несколько платформ, можно использовать разделитель ;
. Чтобы добавить резервную платформу, можно выполнить следующие действия:
<AssetTargetFallback Condition=" '$(TargetFramework)'=='netcoreapp3.1' ">
$(AssetTargetFallback);net472;net471
</AssetTargetFallback>
Оставьте $(AssetTargetFallback)
, если требуется перезаписать вместо добавления к существующим значениям AssetTargetFallback
.
Примечание.
Если вы используете проект на основе пакета SDK для .NET, соответствующие значения $(AssetTargetFallback)
уже настроены и задавать их вручную не требуется.
Ранее для устранения этой проблемы использовалась функция $(PackageTargetFallback)
, которая на данный момент не работает и не должна использоваться. Чтобы перейти с $(PackageTargetFallback)
на $(AssetTargetFallback)
, просто измените имя свойства.