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
Content
in your project files, useContentWithTargetPath
when you need to run custom build logic as part of your build that executes after theAssignTargetPaths
target and you missed your chance of yourContent
items 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,
ContentWithTargetPath
items get calculated during the build process sinceContent
does not need to contain aTargetPath
orLink
metadata 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 theTargetPath
metdata existing on theseContentWithTargetPath
items.There is not much use in documenting
ContentWithTargetPath
since you can achieve most things with theContent
item 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 useContent
tooling (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
ContentWithTargetPath
items are created fromContent
items, build logic running after that step (AssignTargetPaths
target) have to createContentWithTargetPath
items if they want to contribute items that need to be copied/published. This can be the case if you want to hook logic intodotnet publish
that adds additional items to the publish output but which does not need to run ondotnet build
for example.