Русский
Русский
English
Статистика
Реклама

Наследование в Nuget-пакетах

image

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.

Здесь есть несколько решений.

  1. Предложить потребителю пакета ViennaNET.Orm.DB2.Win учитывать транзитивную зависимость от пакета IBM.Data.DB2.Core. Это можно сделать вручную или с помощью автоматизированного инструмента типа ранее упоминаемого мною Paket.
  2. Полностью продублировать в проекте пакета ViennaNET.Orm.DB2.Win содержимое и поведение пакета IBM.Data.DB2.Core.
  3. Реализовать наследование содержимого и поведения пакета IBM.Data.DB2.Core в пакете ViennaNET.Orm.DB2.Win.

Решения 1 и 2 лежат на поверхности, поэтому здесь я опишу только решение 3. Оно позволит упростить использование пакета конечным потребителем и снизит возможные риски копирайта, которые могут возникнуть при дублировании содержимого одного проекта в другом.

После того, как вы скачаете и разархивируете пакет IBM.Data.DB2.Core, вы увидите примерно такую структуру каталога:

image

В папке build находится папка clidriver с unmanaged-драйвером DB2 и targets-скрипт IBM.Data.DB2.Core.targets, который будет выполняться при сборке проекта, использующего этот пакет. Скрипт содержит следующие инструкции:

<Project xmlns="http://personeltest.ru/away/schemas.microsoft.com/developer/msbuild/2003">    <ItemGroup>        <None Include="$(MSBuildThisFileDirectory)clidriver\**" >            <Link>clidriver\%(RecursiveDir)%(FileName)%(Extension)</Link>            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>        </None>    </ItemGroup></Project>

В скрипте говорится, что в проект, который использует данный пакет, на все файлы из папки build\clidriver нужно рекурсивно добавить контент-ссылки. Это необходимо, чтобы в процессе билда файлы с драйверами были помещены в итоговую папку сборки проекта.

После сборки проекта в нем появиться папка с контент-ссылками. Причем это именно ссылки на файлы находящиеся в папке пакета IBM.Data.DB2.Core, в папку проекта они не копируются:

image

Теперь, хотелось бы повторить такое же поведение для пакета ViennaNET.Orm.DB2.Win в отношении его потребителя.

Тут пришлось изрядно порыть MSDN и StackOverflow. Как мне кажется, в итоге сформировалось решение достойное того, чтобы поведать о нем общественности.

Для реализации в вашем пакете наследования контента и поведения от другого пакета достаточно выполнить следующие действия в файле проекта вашего пакета.

  1. В ссылке на базовый пакет вам нужно указать атрибут GeneratePathProperty="true". Это позволит создать переменную процесса сборки с именем, соответствующим имени пакета. Она нам нужна, так как будет указывать путь к папке с содержимым этого пакета. В самом имени символ '.' будет заменен на символ '_'.

    <ItemGroup>    <PackageReference Include="IBM.Data.DB2.Core"         Version="1.3.0.100"         GeneratePathProperty="true" /></ItemGroup>
    
  2. Добавить контент, ссылающийся на контент базового пакета. Символы '**' обозначают рекурсивное использование всех файлов.

    <Content Include="$(PkgIBM_Data_DB2_Core)\build\clidriver\**"     Pack="true" PackagePath="build\clidriver"     PackageCopyToOutput="false" />
    
  3. Добавить контент, ссылающийся на target-скрипт базового проекта. При этом, чтобы его выполнил MsBuild, необходимо переименовать target-скрипт по имени текущего проекта. Это можно сделать в атрибуте 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>..\Bin\ViennaNET.Orm.DB2.Win.xml</DocumentationFile>  </PropertyGroup>  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">    <OutputPath>..\Bin</OutputPath>    <DocumentationFile>..\Bin\ViennaNET.Orm.DB2.Win.xml</DocumentationFile>  </PropertyGroup>  <ItemGroup>    <ProjectReference Include="..\ViennaNET.Orm\ViennaNET.Orm.csproj" />    <ProjectReference Include="..\ViennaNET.Protection\ViennaNET.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)\build\clidriver\**"         Pack="true" PackagePath="build\clidriver"         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.
Источник: habr.com
К списку статей
Опубликовано: 21.01.2021 14:15:10
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Блог компании райффайзенбанк

Net

Ооп

Nuget

Msbuild

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru