Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Сборки используются двумя разными способами во время сборки. Первый связан с компиляцией, которая позволяет коду пользователя пакета компилироваться с использованием API в сборке, и Intellisense предоставлять предложения. Второй — среда выполнения, где сборка копируется в bin каталог и используется во время выполнения программы. Некоторые авторы пакетов хотели бы только собственные сборки (или подмножество своих сборок), доступные потребителям пакетов во время компиляции, но необходимо предоставить все их зависимости для среды выполнения. В этом документе рассматриваются способы достижения этого результата.
Рекомендуется: одна сборка на пакет
Наша рекомендация заключается в наличии одного пакета для каждой сборки и зависимостей пакетов для других сборок. Когда NuGet восстанавливает проект, он выполняет выбор ресурсов и поддерживает включение, исключение и назначение приватными различных классов ресурсов. Чтобы предотвратить превращение зависимостей вашего пакета в ресурсы компоновки времени для всех, кто использует ваш пакет, вы можете сделать compile ресурсы закрытыми. В созданном пакете это приведет compile к исключению из зависимости. Обратите внимание, что частные ресурсы по умолчанию, когда они не указаны, это contentfiles;build;analyzers. Таким образом, следует использовать PrivateAssets="compile;contentfiles;build;analyzers" в вашей PackageReference или ProjectReference.
<ItemGroup>
<ProjectReference Include="..\OtherProject\OtherProject.csproj" PrivateAssets="compile;contentfiles;build;analyzers" />
<PackageReference Include="SomePackage" Version="1.2.3" PrivateAssets="compile;contentfiles;build;analyzers" />
</ItemGroup>
Если вы создаёте пакет из файла nuspec, а не позволяете NuGet автоматически сгенерировать его для вас, необходимо использовать XML-атрибут exclude для nuspec.
<dependencies>
<group targetFramework=".NETFramework4.8">
<dependency id="OtherProject" version="3.2.1" exclude="Compile,Build,Analyzers" />
<dependency id="SomePackage" version="1.2.3" exclude="Compile,Build,Analyzers" />
</group>
</dependencies>
Существует три причины, по которым это рекомендуемое решение.
Во-первых, новые сборки и пакеты часто ссылаются на полезные сборки. Хотя сборка служебной программы может использоваться только одним пакетом сегодня, что делает его заманчивым для отправки обеих сборок в один пакет, если второй пакет хочет использовать "частную" служебную сборку в будущем, либо сборка служебной программы должна быть перемещена в новый пакет, и старый пакет необходимо обновить, чтобы объявить его как зависимость, или пакет служебной программы должен отправляться как в существующий, так и новый пакет. Если сборка поставляется в двух разных пакетах и проект ссылается на оба пакета, если в двух пакетах есть разные версии сборки служебной программы, NuGet не сможет помочь в управлении версиями.
Во-вторых, может наступить момент, когда разработчики, использующие ваш пакет, также захотят использовать API из ваших зависимостей. Например, рассмотрим пакет Microsoft.ServiceHub.Client версии 3.0.3078. Если вы загрузите пакет и проверите файл nuspec, вы увидите, что он перечисляет два пакета, начинающиеся с Microsoft.VisualStudio. в качестве зависимостей, то есть они необходимы во время выполнения, но при этом исключает их компиляционные активы. Это означает, что проекты с помощью Microsoft.ServiceHub.Client не будут иметь API Visual Studio, доступные в IntelliSense или если они создают проект, если только проект явно не устанавливает эти пакеты. И это преимущество зависимости пакета с исключенным ресурсом. Проекты, использующие ваш пакет, если им необходимо использовать ваши зависимости, могут добавить зависимость от пакета, чтобы сделать API доступными для использования.
Наконец, некоторые авторы пакетов были запутаны в прошлом в отношении выбора сборки NuGet для пакетов, поддерживающих несколько целевых фреймворков, когда их пакет также содержит несколько сборок. Если основная сборка поддерживает другие целевые платформы, чем сборка вспомогательной программы, может быть неочевидно, в каких lib/ каталогах следует поместить все сборки. Разделение каждого пакета по имени сборки делает более интуитивно понятным, в какие lib/ папки должна попадать каждая сборка. Обратите внимание, что это не означает наличие Package1.net48 или Package1.net6.0 пакетов. Это означает наличие lib/net48/Package1.dll и lib/net6.0/Package6.0 в Package1, а также lib/netstandard2.0/Package2.dlllib/net5.0/Package2.dll в Package2. Когда Nuget восстанавливает проект, Nuget независимо выбирает ресурсы для двух пакетов.
Учтите также, что включение и исключение ресурсов зависимостей используются только в проектах с использованием PackageReference. Любой проект, устанавливающий ваш пакет с помощью packages.config, установит свои зависимости и также предоставит доступ к своим API-интерфейсам.
packages.config поддерживается только старыми шаблонами проектов .NET Framework Visual Studio. Проекты в стиле SDK, даже те, которые нацелены на .NET Framework, не поддерживают packages.config, и поэтому поддерживают включение/исключение зависимостей.
Не рекомендуется: несколько сборок в одном пакете
PackageReference и packages.config имеют различные функции. Если вы хотите поддерживать потребителей пакетов, которые используют PackageReference, packages.config, или оба, это изменяет то, как вы должны разрабатывать ваш пакет.
Целевой объект пакета MSBuild для NuGet не поддерживает автоматическое включение ссылок на проекты в пакете. В нем будут перечислены только те проекты, на которые ссылается ссылка, в качестве зависимостей пакетов. На сайте GitHub обсуждается проблема, в которой участники сообщества поделились способами достижения этого результата, что обычно включает использование PackagePath метаданных элементов MSBuild для размещения файлов в любой части пакета, как это описано в документации по включению содержимого в пакет и применение SuppressDependenciesWhenPacking, чтобы ссылки на проекты не превращались в зависимости пакетов. Существуют также средства, разработанные сообществом, которые можно использовать в качестве альтернативы официальному пакету NuGet, который поддерживает эту функцию.
PackageReference поддержка
Когда потребитель пакета использует PackageReference, NuGet выбирает ресурсы компиляции и среды выполнения независимо, как описано ранее.
Компиляция ресурсов предпочитает ref/<tfm>/*.dll (например ref/net6.0/*.dll), но если ref/<tfm>/*.dll не существует, она будет использовать lib/<tfm>/*.dll (например lib/net6.0/*.dll).
Ресурсы среды выполнения предпочитают runtimes/<rid>/lib/<tfm>/*.dll (например, (runtimes/win11-x64/lib/net6.0/*.dll)), но если этого не существует, то возвращается на lib/<tfm>/*.dll.
Так как сборки не используются во ref\<tfm>\ время выполнения, они могут быть сборками только метаданных для уменьшения размера пакета.
packages.config поддержка
Проекты, использующие packages.config для управления пакетами NuGet, обычно добавляют ссылки на все сборки в каталогеlib\<tfm>\. Каталог ref\ был добавлен в поддержку PackageReference и поэтому не учитывается при использовании packages.config. Чтобы явно задать, какие сборки ссылаются на проекты с помощью packages.config, пакет должен использовать <references> элемент в файле nuspec. Рассмотрим пример.
<references>
<group targetFramework="net45">
<reference file="MyLibrary.dll" />
</group>
</references>
Целевые объекты пакета MSBuild не поддерживают <references> элемент. Ознакомьтесь с документацией по упаковке с помощью nuspec-файла при использовании пакета MSBuild.
Замечание
packages.config проект использует процесс с именем ResolveAssemblyReference для копирования сборок в выходной bin\<configuration>\ каталог. Сборка вашего проекта копируется, затем система сборки анализирует манифест сборки на наличие упомянутых в нем сборок, копирует эти сборки и рекурсивно повторяет процесс для всех сборок. Это означает, что если какая-либо из сборок, загруженных только отражением (Assembly.LoadMEF или другой платформой внедрения зависимостей), она не может быть скопирована в выходной каталог проекта bin\<configuration>\ , несмотря на то, что она находится в bin\<tfm>\. Это также означает, что это работает только для сборок .NET, а не для машинного кода, вызываемого с помощью P/Invoke.
Поддержка обоих PackageReference и packages.config
Это важно
Если пакет содержит элемент nuspec <references> и не содержит сборки в ref\<tfm>\, NuGet будет объявлять сборки, перечисленные в элементе nuspec <references> , как ресурсы компиляции, так и среды выполнения. Это означает, что возникнут исключения во время выполнения, когда сборкам, которые упоминаются, потребуется загрузить любую другую сборку в каталоге lib\<tfm>\. Поэтому важно использовать nuspec <references> для packages.config поддержки, а также дублирование сборок в папке ref/ для PackageReference поддержки. Папка runtimes/ пакета не должна использоваться, она была добавлена в приведенный выше раздел для завершения.
Example
Мой пакет будет содержать три сборки: MyLib.dll, MyHelpers.dll и MyUtilities.dll, предназначенные для .NET Framework 4.7.2.
MyUtilities.dll содержит классы, предназначенные для использования только другими двумя сборками, поэтому я не хочу сделать эти классы доступными в IntelliSense или во время компиляции проектов с помощью пакета. Файл nuspec должен содержать следующие XML-элементы:
<references>
<group targetFramework="net472">
<reference file="MyLib.dll" />
<reference file="MyHelpers.dll" />
</group>
</references>
Мне нужно убедиться, что содержимое пакета:
lib\net472\MyLib.dll
lib\net472\MyHelpers.dll
lib\net472\MyUtilities.dll
ref\net472\MyLib.dll
ref\net472\MyHelpers.dll