使用.csproj和dotnet pack命令中的MsBuild将文件从Nuget包复制到输出目录

Jér*_*VEL 5 .net c# msbuild nuget .net-standard

上一次我不得不找出如何从Nuget包中提取一些文件的过程至少花了我6个月的时间,但最终我设法找到了解决方案

事实是,此解决方案假定我有一个.nupkg文件并手动添加一个.targets文件以执行提取过程。

现在,情况有所不同:

  1. 我没有任何.nupgk文件,我们使用以下命令在VSTS服务器上自动生成一个文件:dotnet pack命令。然后我们从Nuget服务器中使用软件包
  2. 我们再花6个月时间找不到解决方案

这是我的 ProjectName.csproj

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
        <RestoreProjectStyle>PackageReference</RestoreProjectStyle>
        <Authors>Jérôme MEVEL</Authors>
        <Version>1.0.3</Version>
        <GeneratePackageOnBuild>true</GeneratePackageOnBuild>

        <!-- This answer got many votes on a Github thread so I tried just in case -->
        <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

        <!-- Just trying that too-->
        <IncludeBuildOutput>true</IncludeBuildOutput>
        <IncludeContentInPack>true</IncludeContentInPack>

        <!-- I wanted to see the full generated Nuget package -->
        <IncludeSource>true</IncludeSource>

        <!-- desperate attempt -->     
        <TargetsForTfmSpecificBuildOutput>GetMyPackageFiles</TargetsForTfmSpecificBuildOutput>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Dapper" Version="1.50.5" />
        <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.1.1" />
        <PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.1" />
        <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.1.1" />
        <PackageReference Include="NLog" Version="4.5.8">

            <!-- Let's try this too just in case-->
            <IncludeAssets>all</IncludeAssets>
        </PackageReference>
        <PackageReference Include="NLog.Extensions.Logging" Version="1.2.1">
            <IncludeAssets>all</IncludeAssets>
        </PackageReference>
        <PackageReference Include="NLog.Web.AspNetCore" Version="4.6.0">
            <IncludeAssets>all</IncludeAssets>
        </PackageReference>
        <PackageReference Include="System.Data.Common" Version="4.3.0" />
        <PackageReference Include="System.Data.SqlClient" Version="4.5.1" />
    </ItemGroup>
    <ItemGroup>

        <!-- Added the file to the root folder in case <IncludeAssets>all</IncludeAssets> is looking there -->
        <Content Include="NLog.config">
            <Pack>true</Pack>
            <PackagePath>NLog;;</PackagePath>
            <CopyToOutputDirectory>Always</CopyToOutputDirectory>
        </Content>

        <!-- My desired path to look for the file -->
        <Content Include="NLog\NLog.config">
          <Pack>true</Pack>
          <PackagePath>NLog;;</PackagePath>
          <CopyToOutputDirectory>Always</CopyToOutputDirectory>
        </Content>
    </ItemGroup>

    <!-- This is the default setting, perfectly working when I reference the project instead of installing the Nuget package -->
    <ItemGroup>
        <None Update="NLog\NLog.config">
            <CopyToOutputDirectory>Always</CopyToOutputDirectory>
        </None>
    </ItemGroup>

    <!-- desperate attempt -->
    <Target Name="GetMyPackageFiles">
        <ItemGroup>
            <BuildOutputInPackage Include="NLog/Nlog.config">
                <TargetPath>NLog</TargetPath>
            </BuildOutputInPackage>
        </ItemGroup>
    </Target>
</Project>
Run Code Online (Sandbox Code Playgroud)

如您所见,我尝试了几种不同的设置。此MsBuild生成一个NLog.config文件,该文件包含在NLogNuget软件包文件根目录下的文件夹中。

在此处输入图片说明

在进行不同的尝试期间,根据我设置的配置,最终可以NLog.configsrc/ProjectName.Logging/NLog/NLog.config或什至在结束文件lib/netstandard2.0/Nlog.config

因此,我的文件肯定包含在我的Nuget软件包文件中,但不会复制到使用该软件包的项目的输出目录中。

.nuspec在生成软件包时,我尝试指定一个文件,dotnet pack如此处所述,但我始终无法获得理想的结果(或者只有我NLog.config的软件包包含在Nuget软件包中,或者是所有源文件)。此外,这有一些缺点,如覆盖.csproj文件中的配置或增加无用的复杂性。我相信我想要实现的目标无需使用.nuspec文件(也许我错了)。

我注意到build/ProjectName.targets文件包中缺少该文件,这可能是丢失的部分。那么如何添加这个.targets不手动修改程序包的情况下文件?

还有另一种方法可以将我的配置文件从Nuget包中复制到输出目录中?

我真的希望有人可以帮助我解决这个问题。这是我第二次要执行相同的操作,但略有不同,这又很难做到。

非常感谢

Jér*_*VEL 5

好的,我终于找到了解决方案,其中包括一个.nuspec文件和一个.targets文件。

ProjectName.csproj只需要包括该

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
        <RestoreProjectStyle>PackageReference</RestoreProjectStyle>
        <NuspecFile>ProjectName.Logging.nuspec</NuspecFile>  
    </PropertyGroup>

    <!-- This is just for some projects referencing this project directly instead of the Nuget package -->
    <ItemGroup>
        <Content Include="NLog\NLog.config">
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </Content>
    </ItemGroup>

    <ItemGroup>
        <PackageReference Include="Dapper" Version="1.50.5" />
        <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.1.1" />
        <PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.1" />
        <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.1.1" />
        <PackageReference Include="NLog" Version="4.5.8" />
        <PackageReference Include="NLog.Extensions.Logging" Version="1.2.1" />
        <PackageReference Include="NLog.Web.AspNetCore" Version="4.6.0" />
        <PackageReference Include="System.Data.Common" Version="4.3.0" />
        <PackageReference Include="System.Data.SqlClient" Version="4.5.1" />
    </ItemGroup>
</Project>
Run Code Online (Sandbox Code Playgroud)

ProjectName.nuspec您放入与Nuget软件包相关的所有内容

<?xml version="1.0"?>
<package >
    <metadata>
        <id>ProjectName.Logging</id>
        <version>1.1.0</version>
        <authors>Jérôme MEVEL</authors>
        <description>Just a logging component</description>
        <releaseNotes>Extract the NLog.config file automatically</releaseNotes>
        <dependencies>
            <dependency id="Dapper" version="1.50.5" />
            <dependency id="Microsoft.Extensions.DependencyInjection" version="2.1.1" />
            <dependency id="Microsoft.Extensions.Logging" version="2.1.1" />
            <dependency id="Microsoft.Extensions.Logging.Abstractions" version="2.1.1" />
            <dependency id="NLog" version="4.5.8" />
            <dependency id="NLog.Extensions.Logging" version="1.2.1" />
            <dependency id="NLog.Web.AspNetCore" version="4.6.0" />
            <dependency id="System.Data.Common" version="4.3.0" />
            <dependency id="System.Data.SqlClient" version="4.5.1" />
        </dependencies>
    </metadata>
    <files>
        <file src="bin\Release\netstandard2.0\ProjectName.Logging.dll" target="lib/netstandard2.0/ProjectName.Logging.dll" />    
        <file src="ProjectName.Logging.targets" target="build/ProjectName.Logging.targets" />
        <file src="NLog/Nlog.config" target="content/Nlog.config" />
    </files>
</package>
Run Code Online (Sandbox Code Playgroud)

最后ProjectName.targets小心点!该文件位于计算机的Nuget缓存中。您将可以在Visual Studio中项目的根目录中看到它,而在Windows资源管理器中(至少在Windows中)不能看到它。因此,如果您在Visual Studio中修改文件,它将为该计算机上引用相同Nuget包(和相同版本)的所有其他项目修改文件。

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <ItemGroup>
        <Content Include="$(MSBuildThisFileDirectory)\..\content/NLog.config">
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </Content>
    </ItemGroup>
</Project>
Run Code Online (Sandbox Code Playgroud)

我使用命令生成了Nuget包(现在,我有更多的经验,我知道该文件不能很好地与文件配合使用,存在多个错误),结果如下:dotnet pack nuget packdotnet pack.nuspec

在此处输入图片说明

最后,我可以只安装我的软件包,在构建过程中,Nlog.config文件将从Nuget缓存中复制到项目的输出目录。


小智 5

It is possible to copy files without the .nuspec file, if you create your nuget from the .csproj file as described here.

And to copy files from nuget to output directory, create a ProjectName.targets file with the following content:

<ItemGroup>
    <LogFiles Include="$(MSBuildThisFileDirectory)\..\contentFiles\LogFiles\*.config" />
</ItemGroup>
<Target Name="CopyLogFiles" BeforeTargets="Build">
    <Copy SourceFiles="@(LogFiles)" DestinationFolder="$(TargetDir)CopiedLogFiles\" />
</Target>
Run Code Online (Sandbox Code Playgroud)

In your .csproj file add:

<ItemGroup Label="FilesToCopy">
   <Content Include="ProjectName.targets" PackagePath="build/ProjectName.targets" />
   <Content Include="LogFiles\*.config" Pack="true" PackagePath="contentFiles\LogFiles">
     <PackageCopyToOutput>true</PackageCopyToOutput>
   </Content>
</ItemGroup>
Run Code Online (Sandbox Code Playgroud)

The paths and names can of course be freely chosen.

This should copy all .config files to a folder called CopiedLogFiles in the output directory!

  • 我接受这个答案,因为我认为这是比我更好的解决方案。我认为,对于新的“PackageReference”,最好不要在 Visual Studio 资源管理器中出现任何指向物理位于 Nuget 缓存中的文件的符号链接。否则,在 Visual Studio 中对此文件进行的任何更改也会更改计算机上引用相同 Nuget 包和相同版本的任何其他项目,这很可能不是开发人员希望的行为 (3认同)
  • 感谢您的回答。我刚刚测试了它,它与 `dotnet pack` 和 `PackageReference` 和 `Packages.config` 都能很好地工作。与我的解决方案略有不同:您的方式不会在 Visual Studio 的解决方案资源管理器中创建符号链接,这在我看来并不是一件坏事。 (2认同)

luw*_*wei 5

我认为使用 .Net Standard 库 .csproj 时如何将 nuget contentFiles CopyToOutput 值设置为 true?为这个问题提供了更好的答案。 https://github.com/NuGet/NuGet.Client/pull/1450

您可以PackageCopyToOutput在 .csproj 中设置为 true 以将 nuget 内容文件声明为“CopyToOutput=true”。这样,任何引用 nuget 的项目都会在引用的 csproj 文件中将内容文件标记为<CopyToOutput>true</CopyToOutput>,指示 msbuild 将内容文件复制到输出目录:

在 nuget 项目的 .csproj 中:

<Content Include="...">
    <PackageCopyToOutput>true</PackageCopyToOutput>
</Content>
Run Code Online (Sandbox Code Playgroud)