dotnet publish 包括额外的文件

dotnet publish include extra files

我有一个 netcore 应用程序取决于我的自定义项目。因为我不能直接引用它,所以我写了将我的文件复制到输出的postbuildevents:

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>

当您启动 dotnet publish 命令时,未定义 $(SolutionDir) 宏。结果 xcopy 使用不正确的源路径启动。

缺少解决方案宏的问题是 described here,它仍处于打开状态。我不确定它是否会被修复,因为 $(SolutionDir) 是 IDE-specific 宏。

要解决您的问题,您可以通过开关 /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 publishAfterTargets 的正确值是 Publish,而不是 AfterPublish。我没有找到关于这个事实的明确文档,但是在 this issue.

中提到了它

同时考虑用多个命令替换由换行符分隔的几个 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>

根据 gist that @Jacob 的建议,我已经在 SDK 样式的 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)。发布项目时,select 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 task 的文档的详细信息,请参阅。当你需要复制一个完整的目录结构时,你可能需要复制一个文件夹:

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

关于 SolutionDir 的评论不可用 - 不是作为对问题本身的回答,而是作为需要考虑的事情。

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

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