TL;DR
Is ContentWithTargetPath actually just the internal MSBuild representation of <Content ..><TargetPath>.. or is this really a "proper" MSBuild configuration item?
Only one (1!) of several 100s of our projects contains an entry
<ContentWithTargetPath Include="..\x-model\v6\stuff.json">
<Link>data\stuff.json</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>stuff.json</TargetPath>
</ContentWithTargetPath>
I tried to find any docs for this, but while it is mentioned many times on S.O. here, there does not appear to be any documentation for this MSBuild Item.
What I further found was a mention on one github issue https://github.com/dotnet/msbuild/issues/2795 where ContentWithTargetPath is mentioned together with _NoneWithTargetPath.
I also found the Common MSBuild project items reference where the TargetPath optional sub-entry is listed for <Content ...> (but not for <None ...>, even though None also seems to support it).
Also, as far as I can tell, <TargetPath>in conjunction with CopyToOutputDirectory behaves exactly the same, regardless of whether I use None, Content, or ContentWithTargetPath as element in my actual csproj file.
Can anyone shed some light on why I can find over 50 entries of this MSBuild property here on S.O. but nowhere documented on the MS docs for MSBuild or even prominently in any dotnet github issues? Is there any history to this configuration item?
TL;DR Use
Contentin your project files, useContentWithTargetPathwhen you need to run custom build logic as part of your build that executes after theAssignTargetPathstarget and you missed your chance of yourContentitems being picked up.Unfortunately, a lot of parts in the build process are not fully documented and can only be understood by looking at the actual "code" in MSBuild / the .NET SDK that ships the necessary logic.
As for
ContentWithTargetPath, it is not prefixed with an underscore and thus you can expect that people will try not to make breaking changes to code that creates or uses it.Internally,
ContentWithTargetPathitems get calculated during the build process sinceContentdoes not need to contain aTargetPathorLinkmetadata by default so there is a step that creates an intermediate item that later steps in the build process can rely on - so no other logic (copy-to-output / publish) needs to implement calculating a target path themselves and there is a shared logic to rely on theTargetPathmetdata existing on theseContentWithTargetPathitems.There is not much use in documenting
ContentWithTargetPathsince you can achieve most things with theContentitem when authoring your projects and usually only advanced build customizations need to understand the more internal parts of the build process (for which you'd have to already read the built-in logic anyway). Also this means when people only useContenttooling (e.g. different IDEs) needs to focus on understanding fewer items and not try to be smart about when to use which.There is a small caveat in that after the
ContentWithTargetPathitems are created fromContentitems, build logic running after that step (AssignTargetPathstarget) have to createContentWithTargetPathitems if they want to contribute items that need to be copied/published. This can be the case if you want to hook logic intodotnet publishthat adds additional items to the publish output but which does not need to run ondotnet buildfor example.