Создание пакета NuGet с файлом .exe в качестве файла содержимого

Я пытался включить файл 7za.exe из установленного пакета NuGet 7ZipCLI в проект, для которого я хочу создать пакет NuGet. Пакет NuGet нацелен как на .NET Standard2.0, так и на .NET Framework v4.6.1 +. Я использую возможность Net Standard для создания пакетов NuGet в сборке.

Шрифты отлично копируются в пакет NuGet, но .exe не хочет копировать.

Может ли кто-нибудь помочь мне поместить 7za.exe в папку с содержимым пакета? Это не обязательно должна быть папка содержимого, я просто хочу, чтобы она была скопирована в выходной каталог потребляющего проекта при установке пакета NuGet.

Вот файл .csproj:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
    <Version>1.1.13</Version>
    <TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);IncludeAssemblyReferences</TargetsForTfmSpecificBuildOutput>
    <Platforms>x86</Platforms>
    <PackageId>DocumentGeneration</PackageId>
    <Authors>Me</Authors>
    <Company>Me</Company>
    <Product>DocumentGeneration</Product>
    <Description>A library for creating PDF documents.</Description>
    <PackageTags>Report Certificate Generator iText PDF</PackageTags>
    <AssemblyVersion>1.0.0</AssemblyVersion>
    <FileVersion>1.0.0.0</FileVersion>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
    <OutputPath>$(SolutionDir)Output\</OutputPath>
    <DocumentationFile>$(SolutionDir)Output\DocumentGeneration.xml</DocumentationFile>
    <GenerateResourceUsePreserializedResources>true</GenerateResourceUsePreserializedResources>
    <DebugType>full</DebugType>
    <DebugSymbols>true</DebugSymbols>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
    <OutputPath>$(SolutionDir)Output\</OutputPath>
    <DocumentationFile>$(SolutionDir)Output\DocumentGeneration.xml</DocumentationFile>
    <GenerateResourceUsePreserializedResources>true</GenerateResourceUsePreserializedResources>
    <DebugType>embedded</DebugType>
    <DebugSymbols>true</DebugSymbols>
  </PropertyGroup>

  <ItemGroup>
    <Content Include="Resources\Arial.ttf">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <PackageCopyToOutput>true</PackageCopyToOutput>
      <CopyToPublishDirectory>true</CopyToPublishDirectory>
    </Content>
    <Content Include="Resources\HelveticaNarrow.otf">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <PackageCopyToOutput>true</PackageCopyToOutput>
      <CopyToPublishDirectory>true</CopyToPublishDirectory>
    </Content>
  </ItemGroup>
  
  <ItemGroup Condition="'$(TargetFramework)' == 'net461'">
    <PackageReference Include="iTextSharp" Version="5.5.13.2" />
  </ItemGroup>
  <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0'">
    <PackageReference Include="itextsharp.netstandard" Version="5.5.13.2" GeneratePathProperty="true" />
    <PackageReference Include="System.Drawing.Common" Version="5.0.0" GeneratePathProperty="true" />
    <PackageReference Include="System.Resources.Extensions" Version="5.0.0" />
    <PackageReference Include="System.Resources.ResourceManager" Version="4.3.0" />
  </ItemGroup>
  
  <ItemGroup>
    <PackageReference Include="7ZipCLI" Version="9.20.0" GeneratePathProperty="true" IncludeAssets="all" />
    <PackageReference Include="System.Text.Encoding" Version="4.3.0" />
    <PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
  </ItemGroup>

  <ItemGroup>
    <None Include="readme.txt" pack="true" PackagePath="." />
  </ItemGroup>
  
  <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
    <None Include="$(Pkgitextsharp_netstandard)\lib\netstandard2.0\itextsharp.netstandard.dll">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <PackageCopyToOutput>true</PackageCopyToOutput>
      <Visible>false</Visible>
    </None>
    <Content Include="$(Pkg7ZipCLI)\tools\7za.exe">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <PackageCopyToOutput>true</PackageCopyToOutput>
      <PackagePath>content\Resources;contentFiles\any\any\Resources</PackagePath>
      <Visible>false</Visible>
    </Content>
  </ItemGroup>

  <ItemGroup Condition="'$(TargetFramework)' == 'net461'">
    <Content Include="$(Pkg7ZipCLI)\tools\7za.exe">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <PackageCopyToOutput>true</PackageCopyToOutput>
      <PackagePath>content\Resources;contentFiles\any\any\Resources</PackagePath>
      <Visible>false</Visible>
    </Content>
  </ItemGroup>
    
  <ItemGroup>
    <Compile Update="Properties\Resources.Designer.cs">
      <DesignTime>True</DesignTime>
      <AutoGen>True</AutoGen>
      <DependentUpon>Resources.resx</DependentUpon>
    </Compile>
  </ItemGroup>

  <ItemGroup>
    <EmbeddedResource Update="Properties\Resources.resx">
      <Generator>PublicResXFileCodeGenerator</Generator>
      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
    </EmbeddedResource>
  </ItemGroup>
    
  <Target Name="IncludeAssemblyReferences">
    <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
      <BuildOutputInPackage Include="$(Pkgitextsharp_netstandard)\lib\netstandard2.0\itextsharp.netstandard.dll">
        <Visible>false</Visible>
      </BuildOutputInPackage>
    </ItemGroup>
  </Target>

</Project>

Также вот как сейчас выглядит пакет NuGet:

Текущий пакет NuGet


person Stephan V.d Westhuizen    schedule 27.01.2021    source источник
comment
Вы установили новый пакет в проекте, отличном от SDK, или в проекте new-sdk?   -  person Mr Qian    schedule 27.01.2021
comment
Если я вас правильно понимаю: я бы хотел, чтобы этот проект можно было установить в проекте, все еще использующем pacakges.config, а также PackageReference, но также он устанавливался в .NET Standard и .NET Core.   -  person Stephan V.d Westhuizen    schedule 27.01.2021


Ответы (1)


Если вы просто хотите, чтобы файл выводился в папку bin под packages.config, вам нужно использовать <packages_id>.props файл, а <PackageCopyToOutput>true</PackageCopyToOutput> только для PackageReference.

Кроме того, <CopyToOutputDirectory>Always</CopyToOutputDirectory> предназначен только для локального файла в локальном проекте, а не для пакета nuget. И это не работает для пакета nuget.

Решение

1) добавьте файл с именем DocumentGeneration.props (‹packages_id› .props, а ваш packageID - DocumentGeneration) в папку build.

введите описание изображения здесь

2) измените свой DocumentGeneration.csproj файл:

.....

      <Content Include="$(Pkg7ZipCLI)\tools\7za.exe">
           <CopyToOutputDirectory>Always</CopyToOutputDirectory>
           <PackageCopyToOutput>true</PackageCopyToOutput> 
           <PackagePath>content\Resources;contentFiles\any\any\Resources</PackagePath>
           <Visible>false</Visible>
       </Content>

        <None Include="build\*.*">
           <Pack>true</Pack>
           <PackagePath>build</PackagePath>
        </None>
    
    
.....

3) добавьте в DocumentGeneration.props файл:

<Project>
    <ItemGroup>

        <None Include="$(ProjectDir)Resources\*.*">
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>           
        </None> 
    </ItemGroup>

</Project>

Or

<Project>
        <None Include="$(MSBuildThisFileDirectory)..\content\**\*.*">
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
            <Link>Resources\%(FileName)%(Extension)</Link>
        </None>
 </Project>

4) перепакуйте свой проект библиотеки. При установке этой новой версии выпуска сначала необходимо очистить кеши nuget или удалить все файлы кеша в C:\Users\xxx(current user)\.nuget\packages.

Кроме того, существует аналогичная проблема..

Обновить

Я думаю, что это проблема для функции multi-targetframeworks. И если вы используете GeneratePathProperty для pkg, свойство будет потеряно на другом targetframework. Это довольно странно, и когда вы переходите на <TargetFramework>, все работает хорошо. Поскольку проблема находится под TargetFrameworks с GeneratePathProperty=true. У меня нет другой хорошей идеи для этого, и я не могу найти хорошее решение, чтобы исправить их.

введите описание изображения здесь

И вы должны сообщить об этом на форуме DC или поднять вопрос на github. И когда вы закончите, вы можете поделиться им здесь.

1) Кроме того, поскольку вы используете multi-targetframeoworks, вам также следует использовать папку buildCrossTargeting в nupkg, чтобы включить файл props. См. эту аналогичную проблему .

2) Во-вторых, когда я использую их, чтобы различать их, nuget также не может его упаковать. И это так странно, и я должен убрать это условие.

<ItemGroup  Condition="'$(TargetFramework)'=='net461'">
...
<None Include="7za.exe" Pack="true" PackagePath="content\Resources;contentFiles\any\any\Resources">
...
</ItemGroup>


<ItemGroup  Condition="'$(TargetFramework)'=='netstandard2.0'">
...
<None Include="7za.exe" Pack="true" PackagePath="content\Resources;contentFiles\any\any\Resources">
...
</ItemGroup>

Я считаю, что узел content и contentFiles предназначен для всего проекта, и вы не можете указать условие с targetframeworks во время упаковки их как содержимого. И я знаю, что content и contentFiles являются целями для всего и не могут нацеливаться на targetframework в multi-targetframeworks.

Вы должны использовать это:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
    </PropertyGroup>

...
    <ItemGroup>
        <PackageReference Include="7ZipCLI" Version="9.20.0" GeneratePathProperty="true">
        </PackageReference>
    </ItemGroup>

...

    <Target Name="FunCopy" BeforeTargets="PrePareForBuild">
        <Copy SourceFiles="$(Pkg7ZipCLI)\tools\7za.exe" DestinationFolder="$(ProjectDir)"></Copy>
    </Target>

    
    <ItemGroup>
        <None Include="$(ProjectDir)7za.exe" Pack="true" PackagePath="content\Resources;contentFiles\any\any\Resources">
            <PackageCopyToOutput>true</PackageCopyToOutput>
            <Visible>false</Visible>
            <CopyToOutputDirectory>Always</CopyToOutputDirectory>
        </None>
    </ItemGroup>
    
    <ItemGroup>

        <None Include="build\*.*" Pack="true" PackagePath="build;buildCrossTargeting"></None>
        
    </ItemGroup>
        
...
</Project>
person Mr Qian    schedule 28.01.2021
comment
Я не могу добавить 7za.exe в качестве содержимого вне групп элементов с условиями. Если я добавлю его в то же место, где я добавляю шрифты, переменная $ (Pkg7ZipCLI) еще не установлена ​​и указывает на C: \ tools. Также после того, как я сделал все в предложенном решении, 7za.exe не появился в пакете NuGet и также не был скопирован ни в один из проектов-потребителей (.NET Standard и .NET Framework с package.config) - person Stephan V.d Westhuizen; 28.01.2021
comment
вы можете проигнорировать это. Что вам нужно сделать, так это добавить файл реквизита, а затем упаковать файл реквизита в папку сборки nupkg. Это улучшение. - person Mr Qian; 28.01.2021
comment
Я сделал это в точности так, как вы заявили, это все еще не работает, поскольку $ (Pkg7ZipCLI) не определен и выдает ошибку во время сборки, поэтому проект NuGet не может быть собран, поэтому пакет NuGet никогда не создается. Если я не включу 7za.exe в качестве Contnet, он не будет скопирован, даже если я использую файл .props. (Однако жестко запрограммированная ссылка на папку .NuGet работает, но это неверный подход) - person Stephan V.d Westhuizen; 28.01.2021
comment
Подождите немного, и у меня есть для вас обходной путь. - person Mr Qian; 29.01.2021
comment
Я обновил свой ответ, и вы можете его проверить. - person Mr Qian; 29.01.2021
comment
Большое спасибо!!! Это отлично сработало, спасибо. Мне просто нужно добавить скопированный файл 7za.exe в мой .gitnore, поскольку он копируется при сборке, но отлично работает в CI / CD. Если я устанавливаю пакет в проект с помощью packages.config, ресурсы не помечаются как Копировать всегда / если новее, возможно ли это сделать в файле .props? - person Stephan V.d Westhuizen; 29.01.2021
comment
Собственно, это можно было сделать. Функция файла props работает для проектов, отличных от sdk, с packages.config. Файл для этого. И хотя 7za.exe не установлен на Copy Always, как показывает пользовательский интерфейс, на самом деле он находится в выходной папке. - person Mr Qian; 29.01.2021