Msbuild: How to copy a folder to output directory and keep its root folder?

Created on 2 Feb 2018  路  13Comments  路  Source: dotnet/msbuild

Came from https://github.com/dotnet/project-system/issues/3203

Following steps in @rainersigwald's post, files did have been copied to output folder, but the root folder ("config\" itself) can not be copy to output path. For example:

// Original
config
|--- config.json
|--- config.dev.json

// After build:
output
|--- config.json
|--- config.dev.json

// What I want:
output
|--- config
          |--- config.json
          |--- config.dev.json

Is there any way to keep its root folder too?

Here's the code snippet:

<ItemGroup>
  <Folder Include="$(SolutionDir)config\" CopyToOutputDirectory="Always" />
</ItemGroup>

Most helpful comment

The 2.0 version of the .NET SDK (visual studio 15.4+, .NET CLI 2.0.0+) has a feature that can be used for this: the LinkBase metadata:

<ItemGroup>
  <None Include="$(SolutionDir)config\**" 
        CopyToOutputDirectory="PreserveNewest"
        LinkBase="config\" />
</ItemGroup>

All 13 comments

The 2.0 version of the .NET SDK (visual studio 15.4+, .NET CLI 2.0.0+) has a feature that can be used for this: the LinkBase metadata:

<ItemGroup>
  <None Include="$(SolutionDir)config\**" 
        CopyToOutputDirectory="PreserveNewest"
        LinkBase="config\" />
</ItemGroup>

Depending on which project type you have, the None items may already exist - e.g. for .net standard and .net core projects (non-web projects, web projects would use Content for .json files) and you could just update their CopyToOutputDirectory metadata:

<ItemGroup>
  <None Update="$(SolutionDir)config\**"  CopyToOutputDirectory="PreserveNewest"  />
</ItemGroup>

If you need to do this in non-.net standard/core projects (non-"SDK" projects), you can use the Link metadata:

  <ItemGroup>
    <Content Include="..\sql\**" CopyToPublishDirectory="PreserveNewest" Link="sql\%(RecursiveDir)\%(Filename)%(Extension)" />
  </ItemGroup>

e.g. see https://stackoverflow.com/questions/43569821/dotnet-core-publish-include-exclude-dir-in-output/43611163#43611163

It works. Thank you!

@dasMulli How can we specify the target folder path in the output directory ? Like final it should go in abc/def folder under output directory. This is for .net core projects.

@ashishnegi if you're using this code, you can put the target folder into the LinkBase metadata attribute.

I had to change <None Update to <None Include to make the copy work.

@dasMulli I have following structure:

MyProject.csproj
---Components
------A.dll
------B.dll
---------NestedDir
------------X.dll
------------Y.dll

How to remove the Components directory and put its content to output directory?
Using this code copy Components folder into output directory.

I want this (in output directory):

MyProject.dll
---A.dll
---B.dll
------NestedDir
---------X.dll
---------Y.dll

Use the same code without LinkBase (or set it to \) and add

<PropertyGroup>
  <DefaultItemExcludes>$(DefaultItemsExclude);Components\**\*</DefaultItemExcludes>
</PropertyGroup>

So there won't be conflicting items with different copy metadata.

@dasMulli I got same result. I want to copy Components's content into Output. I don't want to copy Components folder, just its content.

from https://stackoverflow.com/a/35065306/492

<ContentWithTargetPath Include="lib\some_file.dat">
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  <TargetPath>some_file.dat</TargetPath>
</ContentWithTargetPath>

may be worth trying with wildcards. I haven't tried it with wildcards, works fine for just one file.

this worked for me

    <ContentWithTargetPath 
       Include="$(MSBuildThisFileDirectory)..\Files\*.*"
       CopyToOutputDirectory="PreserveNewest"
       TargetPath="Files\%(Filename)%(Extension)" />

Please note that using ContentWithTargetPath currently breaks incremental builds (As in, it will always build the project, even when nothing has changed).

It seems to check the default target path for your file, instead of checking the specified TargetPath, and when the file isn't found at the default path, it concludes that the file is missing and the project must be built again.

If you need to do this in non-.net standard/core projects (non-"SDK" projects), you can use the Link metadata:

  <ItemGroup>
    <Content Include="..\sql\**" CopyToPublishDirectory="PreserveNewest" Link="sql\%(RecursiveDir)\%(Filename)%(Extension)" />
  </ItemGroup>

e.g. see https://stackoverflow.com/questions/43569821/dotnet-core-publish-include-exclude-dir-in-output/43611163#43611163

It seems that this is not working in razor projects.

Was this page helpful?
0 / 5 - 0 ratings