Nuget-пакет — это не только архив с переиспользуемыми сборками, но и контент и target-скрипты, задающие поведение MsBuild при сборке приложения. Это дает нам возможность рассматривать nuget-пакет в качестве самостоятельного объекта, у которого есть состояние и поведение.
А раз у нас есть объект, то что мешает попробовать посмотреть на работу с ним со стороны объектно-ориентированной парадигмы? Давайте попробуем применить для nuget-пакетов один из основных принципов ООП — наследование.
Предположим, вам нужно сделать nuget-пакет на основе уже существующего, немного изменив его поведение.
Для примера, рассмотрим nuget-пакет с драйверами базы данных DB2: IBM.Data.DB2.Core.
Этот пакет обладает специальным поведением. При сборке использующего его проекта происходит копирование unmanaged-библиотеки с драйверами в результирующую папку билда: в проект-потребитель пакета в процессе сборки автоматически добавляются контент-ссылки на файлы unmanaged-библиотек с драйверами.
Предположим, что у вас есть фреймворк, который использует ORM, например — NHibernate. Он содержит специальную обвязку драйвера DB2, которая нужна для обеспечения доступа к этой базе данных через этот ORM: ViennaNET.Orm.DB2.Win.
Сборки внутри ViennaNET.Orm.DB2.Win
конечно же ссылаются на IBM.Data.DB2.Core
. Но если вы в каком-то новом проекте подключите только пакет ViennaNET.Orm.DB2.Win
, то IBM.Data.DB2.Core
автоматически не подключится. То есть, драйвера, необходимые для работы с БД, не появятся, если вы не используете менеджер пакетов, который разрешает транзитивные зависимости. В качестве примера такого менеджера можно упомянуть Paket.
Здесь есть несколько решений.
ViennaNET.Orm.DB2.Win
учитывать транзитивную зависимость от пакета IBM.Data.DB2.Core
. Это можно сделать вручную или с помощью автоматизированного инструмента типа ранее упоминаемого мною Paket.ViennaNET.Orm.DB2.Win
содержимое и поведение пакета IBM.Data.DB2.Core
.IBM.Data.DB2.Core
в пакете ViennaNET.Orm.DB2.Win
.Решения №1 и №2 лежат на поверхности, поэтому здесь я опишу только решение №3. Оно позволит упростить использование пакета конечным потребителем и снизит возможные риски копирайта, которые могут возникнуть при дублировании содержимого одного проекта в другом.
После того, как вы скачаете и разархивируете пакет IBM.Data.DB2.Core
, вы увидите примерно такую структуру каталога:
В папке build
находится папка clidriver
с unmanaged-драйвером DB2 и targets-скрипт IBM.Data.DB2.Core.targets
, который будет выполняться при сборке проекта, использующего этот пакет. Скрипт содержит следующие инструкции:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)clidriver**" >
<Link>clidriver%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
В скрипте говорится, что в проект, который использует данный пакет, на все файлы из папки buildclidriver
нужно рекурсивно добавить контент-ссылки. Это необходимо, чтобы в процессе билда файлы с драйверами были помещены в итоговую папку сборки проекта.
После сборки проекта в нем появиться папка с контент-ссылками. Причем это именно ссылки на файлы находящиеся в папке пакета IBM.Data.DB2.Core
, в папку проекта они не копируются:
Теперь, хотелось бы повторить такое-же поведение для пакета ViennaNET.Orm.DB2.Win
в отношении его потребителя.
Тут пришлось изрядно порыть MSDN и StackOverflow. Как мне кажется, в итоге сформировалось решение достойное того, чтобы поведать о нем общественности.
Для реализации в вашем пакете наследования контента и поведения от другого пакета достаточно выполнить следующие действия в файле проекта вашего пакета.
GeneratePathProperty="true"
. Это позволит создать переменную процесса сборки с именем, соответствующим имени пакета. Она нам нужна, так как будет указывать путь к папке с содержимым этого пакета. В самом имени символ ‘.’ будет заменен на символ ‘_’.
<ItemGroup>
<PackageReference Include="IBM.Data.DB2.Core"
Version="1.3.0.100"
GeneratePathProperty="true" />
</ItemGroup>
<Content Include="$(PkgIBM_Data_DB2_Core)buildclidriver**"
Pack="true" PackagePath="buildclidriver"
PackageCopyToOutput="false" />
PackagePath
.
<Content Include="$(PkgIBM_Data_DB2_Core)build*.targets"
Pack="true" PackagePath="build$(TargetName).targets"
PackageCopyToOutput="false" />
На этом всё.
Теперь при сборке пакета ViennaNET.Orm.DB2.Win
в него будут добавлены файлы unmanaged-драйвера DB2 и target-скрипт из пакета IBM.Data.DB2.Core
. Это позволит при подключении пакета ViennaNET.Orm.DB2.Win
к новому проекту обеспечить размещение драйверов DB2 в папке сборки так, как это происходило бы при подключении пакета IBM.Data.DB2.Core
.
Общий вид файла проекта будет выглядеть так:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<RuntimeIdentifiers>win-x64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<OutputPath>..Bin</OutputPath>
<DocumentationFile>..BinViennaNET.Orm.DB2.Win.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputPath>..Bin</OutputPath>
<DocumentationFile>..BinViennaNET.Orm.DB2.Win.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..ViennaNET.OrmViennaNET.Orm.csproj" />
<ProjectReference Include="..ViennaNET.ProtectionViennaNET.Protection.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="IBM.Data.DB2.Core" Version="1.3.0.100"
GeneratePathProperty="true" />
</ItemGroup>
<ItemGroup>
<Content Include="$(PkgIBM_Data_DB2_Core)buildclidriver**"
Pack="true" PackagePath="buildclidriver"
PackageCopyToOutput="false" />
<Content Include="$(PkgIBM_Data_DB2_Core)build*.targets"
Pack="true" PackagePath="build$(TargetName).targets"
PackageCopyToOutput="false" />
</ItemGroup>
</Project>
Таким способом вы сможете обеспечить наследование контента и поведения в ваших nuget-пакетах от других nuget-пакетов.
Практическую реализацию решения с наследованием контента и поведения nuget-пакетов можно посмотреть в проекте ViennaNET на GitHub.
Центр управления связью общего пользования (ЦМУ ССОП) Роскомнадзора рекомендовал компаниям из реестра провайдеров ограничить доступ поисковых ботов к информации на российских сайтах.…
Apple возобновила переговоры с OpenAI о возможности внедрения ИИ-технологий в iOS 18, на основе данной операционной системы будут работать новые…
Конкурсный управляющий российской «дочки» Google подготовил 23 иска к участникам рекламного рынка. Общая сумма исков составляет 16 млрд рублей –…
Google завершил обновление основного алгоритма March 2024 Core Update. Раскатка обновлений была завершена 19 апреля, но сообщил об этом поисковик…
У частных продавцов на Авито появилась возможность составлять текст объявлений с помощью нейросети. Новый функционал доступен в категории «Обувь, одежда,…
24 апреля 2024 года в Москве состоялась церемония вручения наград международного конкурса Workspace Digital Awards. В этом году участниками стали…