- PVSM.RU - https://www.pvsm.ru -
Nuget-пакет — это не только архив с переиспользуемыми сборками, но и контент с target-скриптами, которые задают поведение MsBuild при сборке приложения. Это дает нам возможность рассматривать nuget-пакет в качестве самостоятельного объекта, у которого есть состояние и поведение.
А раз у нас есть объект, то что мешает попробовать посмотреть на работу с ним со стороны объектно-ориентированной парадигмы? Давайте попробуем применить для nuget-пакетов один из основных принципов ООП — наследование.
Предположим, вам нужно сделать nuget-пакет на основе уже существующего, немного изменив его поведение.
Для примера, рассмотрим nuget-пакет с драйверами базы данных DB2: IBM.Data.DB2.Core [1].
Этот пакет обладает специальным поведением. При сборке использующего его проекта происходит копирование unmanaged-библиотеки с драйверами в результирующую папку билда: в проект-потребитель пакета в процессе сборки автоматически добавляются контент-ссылки на файлы unmanaged-библиотек с драйверами.
Предположим, что у вас есть фреймворк, который использует ORM, например — NHibernate. Он содержит специальную обвязку драйвера DB2, которая нужна для обеспечения доступа к этой базе данных через этот ORM: ViennaNET.Orm.DB2.Win [2].
Сборки внутри ViennaNET.Orm.DB2.Win
конечно же ссылаются на IBM.Data.DB2.Core
. Но если вы в каком-то новом проекте подключите только пакет ViennaNET.Orm.DB2.Win
, то IBM.Data.DB2.Core
автоматически не подключится. То есть, драйвера, необходимые для работы с БД, не появятся, если вы не используете менеджер пакетов, который разрешает транзитивные зависимости. В качестве примера такого менеджера можно упомянуть Paket [3].
Здесь есть несколько решений.
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 [4] и StackOverflow [5]. Как мне кажется, в итоге сформировалось решение достойное того, чтобы поведать о нем общественности.
Для реализации в вашем пакете наследования контента и поведения от другого пакета достаточно выполнить следующие действия в файле проекта вашего пакета.
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 [6].
Автор: Pavel Kulbida
Источник [7]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/net/360878
Ссылки в тексте:
[1] IBM.Data.DB2.Core: https://www.nuget.org/packages/IBM.Data.DB2.Core
[2] ViennaNET.Orm.DB2.Win: https://www.nuget.org/packages/ViennaNET.Orm.DB2.Win
[3] Paket: https://fsprojects.github.io/Paket/
[4] MSDN: https://docs.microsoft.com/en-US/nuget
[5] StackOverflow: https://stackoverflow.com/questions/tagged/nuget
[6] ViennaNET на GitHub: https://github.com/Raiffeisen-DGTL/ViennaNET/blob/master/ViennaNET.Orm.DB2.Win/ViennaNET.Orm.DB2.Win.csproj#L24-L31
[7] Источник: https://habr.com/ru/post/538102/?utm_source=habrahabr&utm_medium=rss&utm_campaign=538102
Нажмите здесь для печати.