Reputation: 10015
I have a netcore application depends on my custom project. Because I cannot reference it directly, I have written postbuildevents that are copying my files to output:
xcopy "$(SolutionDir)Ethereum.Contracts\bin\$(ConfigurationName)\*.abi" "$(TargetDir)" /Y /I
xcopy "$(SolutionDir)Ethereum.Contracts\bin\$(ConfigurationName)\*.bin" "$(TargetDir)" /Y /I
It works fine when I build and run project, but when run publish
command it doesn't include these files.
How can it be done? I tried this approach as well but AddPayloadsFolder
doesn't get called.
My 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 "$(SolutionDir)Ethereum.Contracts\bin\$(ConfigurationName)\*.abi" "$(TargetDir)" /Y /I


xcopy "$(SolutionDir)Ethereum.Contracts\bin\$(ConfigurationName)\*.bin" "$(TargetDir)" /Y /I" />
</Target>
<Target Name="AddPayloadsFolder" AfterTargets="AfterPublish">
<Exec Command="xcopy "$(TargetDir)\*.abi" "$(PublishDir)" /Y /I


xcopy "$(TargetDir)\*.bin" "$(PublishDir)" /Y /I" />
</Target>
</Project>
Upvotes: 19
Views: 16049
Reputation: 663
A comment on SolutionDir being unavailable - not as an answer to the question per se but as something to consider.
If you create a file in your solution directory called "Directory.Build.props", with the following content, then it defines the SolutionDir variable for you:
<Project>
<PropertyGroup>
<SolutionDir>$(MSBuildThisFileDirectory)</SolutionDir>
</PropertyGroup>
</Project>
Upvotes: 1
Reputation: 5696
Based no the gist that @Jacob suggested, I have written down the recommended method to do this in SDK-style csproj files.
You first need to setup an item group that specifies the files that you want to copy. Then you can use a target to perform the actual copy step. This is an example taken from the VS website (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>
You also need to specify when the target needs to be invoked (unless you want to invoke it explicitly). For a normal build you would typically invoked it after the build (AfterBuild
). When publishing the project, select the Publish
target. If it needs to be done both times, then invoke it twice:
<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>
See for more information the documentation about the Copy task. You may need this when you want to copy a folder when you need to copy a complete directory structure:
<Copy SourceFiles="@(MySourceFiles)"
DestinationFiles="@(MySourceFiles->'c:\MyDestinationTree\%(RecursiveDir)%(Filename)%(Extension)')" />
Upvotes: 5
Reputation: 31282
When you launch dotnet publish
command, $(SolutionDir)
macros is not defined. As result xcopy
is launched with incorrect source path.
The issue with missing solution macros is described here and it's still in opened state. I'm not sure it will be ever fixed because $(SolutionDir)
is IDE-specific macros.
To fix your problem, you could pass the value for $(SolutionDir)
macros to dotnet publish
command via switch /p
:
dotnet publish -c Release -r win-x64 /p:SolutionDir="D:\projects\SolutionDir"
You should also add a backslash after $(SolutionDir)
macros:
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="xcopy "$(SolutionDir)\Ethereum.Contracts\bin\$(ConfigurationName)\*.abi" "$(TargetDir)" /Y /I


xcopy "$(SolutionDir)\Ethereum.Contracts\bin\$(ConfigurationName)\*.bin" "$(TargetDir)" /Y /I" />
</Target>
UPDATE (regarding AddPayloadsFolder
target):
AddPayloadsFolder
target defined as
<Target Name="AddPayloadsFolder" AfterTargets="AfterPublish">
is not executed since the correct value of AfterTargets
for dotnet publish
is Publish
, not AfterPublish
. I have not found explicit documentation for this fact, however it is mentioned in this issue.
Also consider replacing several xcopy
commands delimited by newline separator with multiple commands. When I got AddPayloadsFolder
target finally executed, I got an error caused by \r
delimiter appended to the command line.
Summarizing all of the above, here are adjusted PostBuild
and AddPayloadsFolder
targets:
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="xcopy "$(SolutionDir)\Ethereum.Contracts\bin\$(ConfigurationName)\*.abi" "$(TargetDir)" /Y /I" />
<Exec Command="xcopy "$(SolutionDir)\Ethereum.Contracts\bin\$(ConfigurationName)\*.bin" "$(TargetDir)" /Y /I" />
</Target>
<Target Name="AddPayloadsFolder" AfterTargets="Publish">
<Exec Command="xcopy "$(TargetDir)*.abi" "$(PublishDir)" /Y /I" />
<Exec Command="xcopy "$(TargetDir)*.bin" "$(PublishDir)" /Y /I" />
</Target>
Upvotes: 15