[.NET, ООП] Наследование в Nuget-пакетах  
    
    
        
    
    
    
    
            
    
        
            
                
                                    
                
                                    
                
                    
                
            
        
    
    
        
            
                
                
                    
                           
                    
                        Автор 
                        Сообщение 
                    
                                        
                        
                            
                                
                                
                                                                                                            news_bot ®
                                                                        
                                                                                                                                                
                                                                            
                                                                                                                
                                            Стаж: 7 лет 8 месяцев                                        
                                                                                                                
                                            Сообщений: 27286                                        
                                                                                                                                                
                                                             
                            
                                
                             
                         
                        
                            
                                
                                    
                                        
                                        
 
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>
В скрипте говорится, что в проект, который использует данный пакет, на все файлы из папки build\clidriver нужно рекурсивно добавить контент-ссылки. Это необходимо, чтобы в процессе билда файлы с драйверами были помещены в итоговую папку сборки проекта.
После сборки проекта в нем появиться папка с контент-ссылками. Причем это именно ссылки на файлы находящиеся в папке пакета 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)\build\clidriver\**"
 Pack="true" PackagePath="build\clidriver"
 PackageCopyToOutput="false" />
- Добавить контент, ссылающийся на 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
===========
Похожие новости:
- [.NET, Проектирование и рефакторинг, C#, Профессиональная литература] Внедрение зависимостей для начинающих (перевод)
 
- [.NET, C#] Nuke. Быстрый старт
 
- [Тестирование IT-систем, Системное администрирование, Программирование, ООП, DevOps] Востребованные IT-профессии. Свежая аналитика по России
 
- [.NET, C#, DevOps] Как установить файл конфигурации в .Net Core Console app для нескольких сред разработки при запуске Docker-контейнера
 
- [IT-инфраструктура, Серверное администрирование, Конференции] DGTL Communications Meetup 21/01
 
- [.NET] Когда программисту нечего делать или оптимизируем код при помощи Linq.Expression
 
- [Программирование, C, ООП] Трюки с виртуальной памятью (перевод)
 
- [.NET, Системы сборки] xUnit тестирование в TeamCity
 
- [Программирование, .NET, Amazon Web Services, C#, DevOps] Nuke: настраиваем сборку и публикацию .NET-проекта
 
- [.NET, Разработка игр, Unity, CGI (графика), AR и VR] Поговорим про градиенты в Unity
Теги для поиска: #_.net, #_oop (ООП), #_nuget, #_.net, #_msbuild, #_oop (ооп), #_blog_kompanii_rajffajzenbank (
Блог компании Райффайзенбанк
), #_.net, #_oop (
ООП
)
                                        
                                        
                                        
                                     
                                    
                                    
                                                                    
                                                                                             
                         
                        
                            
                                                                    
                                                             
                         
                    
                    
                
                
            
        
    
    
    
    
    
            
    
            
    
        
    
    
        
                        Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
    
    
        
        Текущее время: 31-Окт 23:40
Часовой пояс: UTC + 5 
            
    
                
| Автор | Сообщение | 
|---|---|
| news_bot ® 
                                                                            
                                                                                                                
                                            Стаж: 7 лет 8 месяцев                                         | |
|  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 и №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> В скрипте говорится, что в проект, который использует данный пакет, на все файлы из папки build\clidriver нужно рекурсивно добавить контент-ссылки. Это необходимо, чтобы в процессе билда файлы с драйверами были помещены в итоговую папку сборки проекта. После сборки проекта в нем появиться папка с контент-ссылками. Причем это именно ссылки на файлы находящиеся в папке пакета IBM.Data.DB2.Core, в папку проекта они не копируются:  Теперь, хотелось бы повторить такое же поведение для пакета ViennaNET.Orm.DB2.Win в отношении его потребителя. Тут пришлось изрядно порыть MSDN и StackOverflow. Как мне кажется, в итоге сформировалось решение достойное того, чтобы поведать о нем общественности. Для реализации в вашем пакете наследования контента и поведения от другого пакета достаточно выполнить следующие действия в файле проекта вашего пакета. 
 На этом всё. Теперь при сборке пакета 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 =========== Похожие новости: 
 Блог компании Райффайзенбанк ), #_.net, #_oop ( ООП ) | |
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
    Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 31-Окт 23:40
Часовой пояс: UTC + 5 
