使用dotnet pack命令包含所有依赖项

31
6个回答

41
截至2020年,目前还没有官方支持的方法来实现这一点。然而,一些人已经想出了实现的方法,目前最好的方法是安装由了不起的Teroneko准备的NuGet包。然后,您只需要编辑您的.csproj文件,将所有项目都标记为PrivateAssets="all",根据包的README进行更新。
如果您无法安装上述的 NuGet 包,您可以通过编辑您的 .csproj 文件来实现相同的效果(再次感谢 Teroneko 发现了这个方法 - 它本质上就是他创建的 NuGet 包所做的):
<Project>
  <PropertyGroup>
    <TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
  </PropertyGroup>
  
  <Target Name="CopyProjectReferencesToPackage" DependsOnTargets="BuildOnlySettings;ResolveReferences">
    <ItemGroup>
      <!-- Filter out unnecessary files -->
      <_ReferenceCopyLocalPaths Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'All'))"/>
    </ItemGroup>

    <!-- Print batches for debug purposes -->
    <Message Text="Batch for .nupkg: ReferenceCopyLocalPaths = @(_ReferenceCopyLocalPaths), ReferenceCopyLocalPaths.DestinationSubDirectory = %(_ReferenceCopyLocalPaths.DestinationSubDirectory) Filename = %(_ReferenceCopyLocalPaths.Filename) Extension = %(_ReferenceCopyLocalPaths.Extension)" Importance="High" Condition="'@(_ReferenceCopyLocalPaths)' != ''" />

    <ItemGroup>
      <!-- Add file to package with consideration of sub folder. If empty, the root folder is chosen. -->
      <BuildOutputInPackage Include="@(_ReferenceCopyLocalPaths)" TargetPath="%(_ReferenceCopyLocalPaths.DestinationSubDirectory)"/>
    </ItemGroup>
  </Target>
</Project>

与软件包一样,您可以在.csproj中使用PrivateAssets="all"来标记所依赖的项目引用,然后它就可以正常工作了。

我正在尝试,但这根本不起作用...在管道上遇到以下问题:" ##[error]错误:进程'C:\Program Files\dotnet\dotnet.exe'以退出代码1失败 ##[error]尝试打包文件时发生错误。 " - Seabizkit
3
谢谢,这太棒了,可能是我做的。:D(在这里您可以找到上述行的源代码。我决定也将其作为提供) - Teneko
2
@Teroneko,我不知道你在这里有账号 - 我已经更新了答案,包括你的程序包,并将答案转换为社区维基,以便我不会因此获得信用(当我第一次发布它时应该这样做)。如果你愿意,你可以发表自己的答案,并附上指向你的程序包的链接,以便从中受益的人们给予你应得的声誉 - 如果你这样做,我将标记此答案以删除,以便你的答案成为规范。 - Ian Kemp
标记为正确,因为现在还没有方法,也很可能永远不会有。 - Marcus
1
这与 --no-build 标志不兼容(在 AppVeyor 上是默认行为),因为它由于 DependsOn 的原因隐式地调用了(重新)构建。dotnet pack -c release -o pack --no-build 会产生错误 error NETSDK1085: The 'NoBuild' property was set to true but the 'Build' target was invoked. - riezebosch
显示剩余2条评论

8

我一直在寻找这个答案,但很不爽地发现找不到一个明显的解决方案。对于我最好的解决方法是创建nuspec,在spec中添加我想要在nupkg中的DLL列表,然后使用dotnet pack进行构建。我在这里创建了一个简单的示例和readme - nuget示例应用程序


这种方法对我也适用(Ian Kemp的方法也是)。对我来说,这种方法比Ian的回答更加“正规” - 你不必向任何人解释.csproj文件中所有内容的作用。在.nuspec文件中包含有关依赖项的信息感觉更自然。 - OutstandingBill
2
这种方法对于我需要在软件包内部获得更多控制的情况非常有效。只要注意在.csproj文件中,在<PropertyGroup>中有<NuspecFile>./relative/path/to.nuspec</NuspecFile>允许我们使用dotnet pack命令与.nuspec文件。 - Yas Ikeda

7

解决问题的另一种方法是创建一个定制的.targets文件并将其包含在项目中。您可以添加一些msbuild指令来包含需要放入软件包中的文件。这里有一些文档,告诉您如何操作,以下是一个简短的示例:

<PropertyGroup Condition="$(PackAsComponent) != ''">
  <TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CustomBuildOutput</TargetsForTfmSpecificBuildOutput>
  <TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);CustomContentInPackage</TargetsForTfmSpecificContentInPackage>
</PropertyGroup>

<Target Name="CustomBuildOutput">
  <ItemGroup>
    <BuildOutputInPackage Include="$(OutputPath)*.dll" Exclude="$(TargetPath)" />
    <BuildOutputInPackage Include="$(OutputPath)*.pdb" />
    <BuildOutputInPackage Include="$(OutputPath)*.exe" Exclude="$(TargetPath)" />
  </ItemGroup>
</Target>

<Target Name="CustomContentInPackage">
  <ItemGroup>
    <TfmSpecificPackageFile Include="abc.txt">
    <PackagePath>mycontent/$(TargetFramework)</PackagePath>
    </TfmSpecificPackageFile>
  </ItemGroup>
</Target>

基本上,当我在项目中设置PackAsComponent属性时,我会激活它。这样可以完全保留“dotnet pack”功能,无需指定任何参数。

1
是的,这是为高级场景设计的。需要对MSBuild有很深刻的理解,但一旦掌握了它,你就可以做很多事情。干得好! - Teneko

0

我假设行为是不同的,否则 Octo 不会帮助 OP?你的答案应该尝试解释 Octo 有哪些功能上的不同,从而解决了 OP 的问题。 - Immortal Blue
是的,据我所知,“老派”的工具octo.exe和nuget.exe基本上只会将bin/debug文件夹压缩为一个文件,并添加一些元数据将该文件命名为“.nupkg”。然而,无论如何,我现在已经不明白这个线程中的问题了。为了实现OP所要求的功能,现在是不是只需使用dotnet cli运行dotnet publish命令即可? - Efrain

0
在我的情况下,Ian Kemp 提出的建议解决方案不适用,因为将 PrivateAssets="all" 添加到我的 ProjectReference 会将其从我的包的 <dependencies> 中移除。
我还尝试了 GlennSills 的解决方案,即定义一个 .nuspec 文件,但是这样我就需要手动维护 <dependencies> 部分。
对我来说,最优的解决方案是在 .csproj 中定义所有内容(而不是 .nuspec)。所以,我做了类似于 Ian Kemp 的事情,但我不需要添加 PrivateAssets="all"。
以下是我需要添加到我的 .csproj 中的内容:
<PropertyGroup>
    <TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
  </PropertyGroup>
  
  <Target Name="CopyProjectReferencesToPackage" DependsOnTargets="BuildOnlySettings;ResolveReferences">    
    <ItemGroup>
      <BuildOutputInPackage Include="$(OutputPath)MyReference.dll" TargetPath=""/>
    </ItemGroup>
  </Target>  

这个解决方案在使用dotnet pack命令时非常有效。

这并没有回答问题。一旦你拥有足够的声望,你就可以评论任何帖子;相反,提供不需要提问者澄清的答案。- 来自审查 - undefined

-5

希望这能对您有所帮助。

nuget pack yournuspecfile.nuspec -properties Configuration=Release -IncludeReferencedProjects

或者您的其他命令。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接