Почему мой стандартный пакет NuGet.NET запускает так много зависимостей?

Я сбрасывал с проект .NET Standard и NuGet. У меня есть рабочий проект и загрузил его на NuGet.org. Мой проект нацелен на .NET Standard 1.3, который должен поддерживать.NET Framework 4.6 и .NET Core 1.0.

Но когда я попытался добавить свой проект (через NuGet) в новый проект .NET Framework 4.6, зависимости были разрешены для 47 пакетов! Все они являются системными библиотеками и являются зависимыми от Microsoft.NETCore.Platforms или NETStandard.Library 1.6.1. (Gist полного выхода PM.)

Мой проект импортирует (using) несколько библиотек, ни один из которых я не добавил вручную; то есть все библиотеки, которые "поставляются с" стандартом .NET. Эти библиотеки:

  • Система
  • System.Text
  • System.Reflection
  • System.Linq
  • System.Collections.Generic;

Дело в том, что я решил сделать свой проект целевым .NET Standard, потому что я хотел, чтобы он работал без проблем в приложениях .NET Framework и .NET Core. Я думал, что все, что нужно Стандарту, - установить минимальный уровень совместимости. По-видимому, я предположил (возможно, ошибочно), что библиотеки, такие как System.Console, будут автоматически доступны либо в Core, либо в Framework.

Я не заметил ничего подобного, когда тестировал свой стандартный проект как зависимость в проекте Framework и Core в рамках одного и того же решения, поэтому я подозреваю, что это может быть NuGet.

Что здесь происходит? И как я могу сделать свою библиотеку .NET Standard доступной на NuGet без огромного списка зависимостей?

Это проблема с тем, как я определил свой пакет NuGet? Или я в корне неправильно понял что-то?

Ответ 1

Вы ничего не сделали неправильно, это должно произойти. Если вы хотите, чтобы ваша новая DLL была добавлена ​​в новый проект .NET Framework, вам нужно настроить таргетинг на .NET Standard 2.0 для вашей библиотеки, ожидая версию .NET Framework, которая изначально поддерживает как API, так и версии сборки. для 4.7.2 (в то время как .NET Framework 4.7.1 поддерживает все API-интерфейсы, были ошибки в том, как некоторые сборки были версиями, и поэтому инструментарий (VS 2017 15.5+) добавит дополнительные сборки, чтобы исправить это).

То, что вы видите, является побочным эффектом создания .NET-стандарта и поддержки поддерживаемых фреймворков. Это также зависит от выбранной вами стандартной версии .NET и инструментария, используемого для ссылки на пакет библиотеки.

В .NET Standard < 2.0, вы ссылаетесь на мета-пакет NETStandard.Library, который, в свою очередь, ссылается на дополнительные пакеты (System.*). Эти пакеты содержат эталонные сборки, которые составляют "Стандартный контракт стандарта .NET" - набор API-интерфейсов и имен сборки + версии.

Когда пакет NuGet, который вы создаете для .NET Standard 1.0-1.6, затем ссылается на приложение, эти отдельные пакеты не приводят к сборкам ссылок, а скорее сборку реализации для рамки, на которую нацелено приложение.

Для .NET Core они соответствуют сборкам, которые уже являются частью среды выполнения, поэтому файлы DLL не будут располагаться рядом с встроенным приложением. Однако это изменилось, когда был выпущен новый пакет пакетов для .NET Core 1.1 (NETStandard.Library версия 1.6.1). Это привело к созданию приложений, созданных для .NET Core 1.0, в результате чего были созданы новые сборки для реализации, которые должны были быть включены в .NET Core 1.1 (к счастью, в версии 1.1 была использована "долгосрочная поддержка", поскольку это вызвало дискуссию о том, какие сборки являются частью обещания LTS).

В .NET Framework эти библиотеки (за некоторыми исключениями, такие как System.Net.Http) мало что делают - они просто пересылают системные сборки. Так, например, "контракт" определяет, что System.Object определяется в сборке System.Runtime.dll. Таким образом, файл System.Runtime.dll, в котором вы попадаете в приложении .NET Framework, содержит System.Runtime.dll, который содержит тип forward to.NET Framework mscorlib.dll..NET Core уже содержит другой System.Runtime.dll, который делает что-то другое для этой платформы. Этот механизм позволяет одному DLL файлу работать на обеих платформах, поскольку эти типы вперед и дополнительные реализации обеспечивают тот же "контракт" (типы + сборки или сборки), работающие на обеих реализациях.

.NET Standard 2.0 направлен на сокращение количества пакетов и DLL, необходимых, а также на удаление требуемых обновлений до NETStandard.Library при выпуске новой версии .NET Core.

Итак, для .NET Standard 2.0 и .NET Core 2.0 пакет NETStandard.Library содержит только сборки ссылок для компиляции кода для проекта, но полученный пакет NuGet больше не зависит от этого пакета. Поэтому, когда вы создаете библиотеку с таргетингом на .NET Standard 2.0 и публикуете ее, она не будет иметь зависимостей NuGet (если вы не добавите дополнительные).

Логика того, что "библиотеки поддержки" вводить при использовании библиотеки .NET Standard, была перенесена на оснастку, которая используется во время сборки. Поэтому, когда библиотека, содержащая ссылку на netstandard.dll, добавляется в проект .NET Framework, инструментарий затем добавляет необходимые DLL файлы поддержки на основе используемой версии .NET Framework. Это было сделано для .NET Standard 2.0, а также для .NET Standard 1.5+, поскольку .NET Framework 4.6.1 ретроактивно была совместима с .NET Standard 2.0 (ранее была 1.4) с помощью этих DLL файлов. Тот же инструмент также гарантирует, что даже если пакеты NuGet каким-то образом включены в такой проект приложения, любые библиотеки реализации .NET Standard, созданные через NuGet, удаляются из сборки. Поэтому, если вы ссылаетесь на пакет .NET Standard 1.0 NuGet, который был создан при выпуске .NET Core 1.0, все его зависимости NuGet обрезаются, и вместо этого вы получаете библиотеки поддержки, поставляемые с инструментами построения.

Идея заключалась в том, что .NET Framework 4.7.1 будет содержать все необходимые сборки "inbox", так что netstandard.dll, System.Runtime.dll и т.д. являются частью .NET Framework и любого DLL файла .NET Standard 1.0-2.0 будет "просто работать", проблема в том, что эти DLL файлы "inbox" имели слишком низкий номер версии для некоторых сборок, поэтому библиотеки не могли загрузиться - это было исправлено путем изменения инструментария снова, чтобы включить DLL файлы с более высокими номерами версий в качестве поддержки библиотеки, которые, в свою очередь, переходят к сборкам "входящих".NET Framework. Это планируется установить в .NET Framework 4.7.2.

Ответ 2

Я тоже столкнулся с этой проблемой. Сообщение в блоге, которое вы связали в комментарии к ответу Мартина Уллриха, привело меня к решению, которое сработало для меня: использование многоцелевого таргетинга NuGet. Путем изменения:

<TargetFramework>netstandard1.0</TargetFramework>

в

<TargetFrameworks>netstandard1.0;netstandard2.0;net45</TargetFrameworks>

в файле проекта .csproj. Это приводит к тому, что проект NETStandard.Library отдельно для каждой целевой инфраструктуры, и полученный пакет NuGet зависит только от NETStandard.Library для netstandard1.0. Поскольку NuGet выбирает двоичные файлы net45 для любой полной версии .NET Framework, это позволяет избежать ненужных зависимостей при установке пакета.

Ответ 3

Если вы работаете в .NET 4.6 и пытаетесь выяснить, какие из них вам нужно развернуть, найдите в своем файле CSPROJ \System. (не регулярное выражение) - это те пакеты в пакетах, которые должны быть скопированы с вашим приложением, остальные должны быть фреймворковыми DLL.

Чтобы проверить эту теорию, избавьтесь от них в вашей локальной сборке и запустите ее, чтобы убедиться, что развернутая версия не сломается...

  • В папке bin выполните команду dir/b System*.dll > textfile.txt чтобы получить список библиотек DLL.
  • вставил "DEL" перед всеми именами,
  • Я также нашел Microsoft.Win32.Primitives.dll и netstandard.dll которые не были нужны в 4.6 также.
  • и сохраните его как файл .CMD - ну, не в папке bin, хорошо?
  • добавьте его как процесс пост-сборки. $(ProjectDir)DeleteSuperfluousSystemDlls.cmd

Я хотел бы выйти из .NET 4.6, но AutoCAD плохо работает, когда среда слишком современная для этого.

редактировать...

Вот какая-то копия-паста...

Шаг 1 - в вашем файле CSPROJ...

<!--https://stackoverflow.com/info/2387456/msbuild-exec-task-without-blocking/21181071#21181071-->
  <!--Launch a Process in Parallel-->
  <UsingTask TaskName="ExecAsync" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
    <ParameterGroup>
      <!--The file path is the full path to the executable file to run-->
      <FilePath ParameterType="System.String" Required="true" />
      <!--The arguments should contain all the command line arguments that need to be sent to the application-->
      <Arguments ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Code Type="Fragment" Language="cs"><![CDATA[
  System.Diagnostics.ProcessStartInfo processStartInfo = new System.Diagnostics.ProcessStartInfo(FilePath, Arguments);
  processStartInfo.UseShellExecute = true;
  System.Diagnostics.Process.Start(processStartInfo);
  ]]></Code>
    </Task>
  </UsingTask>
  <Target Name="AfterBuild">
    <ExecAsync FilePath="$(ProjectDir)\Deployment\DeleteSuperfluousSystemDlls.cmd" Arguments="$(TargetDir)" />
  </Target>

Шаг 2. Пакетный файл...

Отредактируйте список, созданный dir/b System*.dll > textfile.txt чтобы он выглядел примерно так

del %1Microsoft.Win32.Primitives.dll
del %1netstandard.dll
del %1System.AppContext.dll
del %1System.Collections.Concurrent.dll
del %1System.Collections.dll
del %1System.Collections.NonGeneric.dll
del %1System.Collections.Specialized.dll
del %1System.ComponentModel.dll

но не забудьте удалить те, которые действительно нужны, чтобы они не были удалены.