.NET发布包含额外文件

18

我有一个依赖于我的自定义项目的NetCore应用程序。因为我不能直接引用它,所以我编写了后置构建事件来将我的文件复制到输出目录:

xcopy "$(SolutionDir)Ethereum.Contracts\bin\$(ConfigurationName)\*.abi" "$(TargetDir)" /Y /I
xcopy "$(SolutionDir)Ethereum.Contracts\bin\$(ConfigurationName)\*.bin" "$(TargetDir)" /Y /I

在构建和运行项目时一切都正常,但是当运行 publish 命令时它不包括这些文件。

该怎么做呢?我尝试了这种方法,但 AddPayloadsFolder 没有被调用。

我的 csproj 文件:

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\..\Dependencies\Dependencies.csproj" />
  </ItemGroup>

  <ItemGroup>
    <None Update="appsettings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="log4net.config">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>

  <Target Name="PostBuild" AfterTargets="PostBuildEvent">
    <Exec Command="xcopy &quot;$(SolutionDir)Ethereum.Contracts\bin\$(ConfigurationName)\*.abi&quot; &quot;$(TargetDir)&quot; /Y /I&#xA;&#xA;&#xD;&#xA;xcopy &quot;$(SolutionDir)Ethereum.Contracts\bin\$(ConfigurationName)\*.bin&quot; &quot;$(TargetDir)&quot; /Y /I" />
  </Target>

  <Target Name="AddPayloadsFolder" AfterTargets="AfterPublish">
    <Exec Command="xcopy &quot;$(TargetDir)\*.abi&quot; &quot;$(PublishDir)&quot; /Y /I&#xA;&#xA;&#xD;&#xA;xcopy &quot;$(TargetDir)\*.bin&quot; &quot;$(PublishDir)&quot; /Y /I" />
  </Target>

</Project>
3个回答

12
当您启动dotnet publish命令时,$(SolutionDir)宏未定义。因此,xcopy将以不正确的源路径启动。
缺少解决方案宏的问题在此处描述,并且仍处于打开状态。我不确定它是否会被修复,因为$(SolutionDir)是特定于IDE的宏。
要解决问题,您可以通过开关/p$(SolutionDir)宏的值传递给dotnet publish命令:

dotnet publish -c Release -r win-x64 /p:SolutionDir="D:\projects\SolutionDir"

您还应在$(SolutionDir)宏后添加反斜杠:
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
    <Exec Command="xcopy &quot;$(SolutionDir)\Ethereum.Contracts\bin\$(ConfigurationName)\*.abi&quot; &quot;$(TargetDir)&quot; /Y /I&#xA;&#xA;&#xD;&#xA;xcopy &quot;$(SolutionDir)\Ethereum.Contracts\bin\$(ConfigurationName)\*.bin&quot; &quot;$(TargetDir)&quot; /Y /I" />
</Target>

更新(关于AddPayloadsFolder目标):

AddPayloadsFolder目标定义为

<Target Name="AddPayloadsFolder" AfterTargets="AfterPublish">

由于dotnet publish的正确值为Publish,而不是AfterPublish,因此未执行。我没有找到明确的文档来证明这一事实,但在此问题中提到了它。
另外,请考虑用多个命令替换由换行符分隔的几个xcopy命令。当最终执行AddPayloadsFolder目标时,我遇到了一个由于命令行附加了\r分隔符而导致的错误。
总结以上所有内容,以下是调整后的PostBuildAddPayloadsFolder目标:
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
    <Exec Command="xcopy &quot;$(SolutionDir)\Ethereum.Contracts\bin\$(ConfigurationName)\*.abi&quot; &quot;$(TargetDir)&quot; /Y /I" />
    <Exec Command="xcopy &quot;$(SolutionDir)\Ethereum.Contracts\bin\$(ConfigurationName)\*.bin&quot; &quot;$(TargetDir)&quot; /Y /I" />
</Target>

<Target Name="AddPayloadsFolder" AfterTargets="Publish">
    <Exec Command="xcopy &quot;$(TargetDir)*.abi&quot; &quot;$(PublishDir)&quot; /Y /I" />
    <Exec Command="xcopy &quot;$(TargetDir)*.bin&quot; &quot;$(PublishDir)&quot; /Y /I" />
</Target>

我将此文件复制到 bin\Debug\netcoreapp2.0 文件夹中(与 Visual Studio 发布选项一样)。然而,\bin\Debug\netcoreapp2.0\publish 仍未包含这些文件。这就是 AddPayloadsFolder 任务的目的。您可以尝试自己添加任何不属于项目的文本文件。例如,尝试将 csproj 文件本身复制到输出目录中。您可以轻松地将其复制到 bin/debug 文件夹中,但它不会进入 publish 文件夹。 - Alex Zhukovskiy
谢谢,它按预期工作。我没有将其分成更易读的“Exec”,因为这是在Visual Studio中生成的方式,否则只有第一个命令会显示在VS项目属性中。 - Alex Zhukovskiy
8
谢谢,有效。但我更喜欢这样:https://gist.github.com/jakubsuchybio/7efe6aa1147f088072459a39837f2ecd - Jacob

4

根据gist@Jacob建议,我已经写下了在SDK-style csproj文件中执行此操作的推荐方法。

首先,您需要设置一个项目组,指定要复制的文件。然后,您可以使用目标来执行实际的复制步骤。这是从VS网站(link)中摘取的示例:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 <ItemGroup>
  <MySourceFiles Include="a.cs;b.cs;c.cs"/>
 </ItemGroup>
 <Target Name="CopyFiles">
  <Copy SourceFiles="@(MySourceFiles)" DestinationFolder="c:\MyProject\Destination" />
 </Target>
</Project>

除非您想显式调用它,否则还需要指定目标需要在何时被调用。对于普通构建,通常会在构建之后调用它 (AfterBuild)。发布项目时,请选择Publish目标。如果需要两次执行,则需要调用两次:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 <ItemGroup>
  <MySourceFiles Include="a.cs;b.cs;c.cs"/>
 </ItemGroup>
 <Target Name="CopyExtraFiles" AfterTargets="AfterBuild">
  <Copy SourceFiles="@(MySourceFiles)" DestinationFolder="c:\MyProject\Destination" />
 </Target>
 <Target Name="PublishExtraFiles" AfterTargets="Publish">
  <Copy SourceFiles="@(MySourceFiles)" DestinationFolder="c:\MyProject\Destination" />
 </Target>
</Project>

有关复制任务的文档,请参阅更多信息。当您需要复制完整目录结构时,可能需要此功能以复制文件夹:

<Copy SourceFiles="@(MySourceFiles)"
      DestinationFiles="@(MySourceFiles->'c:\MyDestinationTree\%(RecursiveDir)%(Filename)%(Extension)')" />

1

关于无法使用SolutionDir的评论——不是针对问题本身的答案,而是要考虑的一些内容。

如果您在解决方案目录中创建一个名为“Directory.Build.props”的文件,并包含以下内容,则可以为您定义SolutionDir变量:

<Project>
 <PropertyGroup>
    <SolutionDir>$(MSBuildThisFileDirectory)</SolutionDir>
 </PropertyGroup>
</Project>

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