Including content files in .csproj that are outside the project cone

You need to add file as a link:

  1. Right click on the project in VS.
  2. Add -> Existing Item...
  3. Find the file.
  4. Select it and.
  5. Add as a Link (drop down in the Add Button in the dialog).
  6. Open the properties of the file and set "Copy to Output Directory" to "Copy always".

BUT You cannot do it for the directory tree.
Instead you need to write post-build task for that. This is a sample that will get you stared.


The answer of Mandark adds the content files directly to the solution, and they will show up in the solution explorer. Whenever a file is added or deleted in the original directory, this is not picked up by visual studio automatically. Also, whenever a file is deleted or added in the solution explorer, the project file is altered, and all files are included separately, instead of just including the folder.

To prevent this, you can use the same trick, but put it in a separate project file and then import it.

The project file (for example include.proj) looks like this:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Content Include="..\..\MyContentFiles\**">
  <Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

In your own project file, add the following line

<Import Project="include.proj" />

Visual Studio will not mess with this file, and just adds files as content during a build. Changes in the original directory are always included. The files won't show up in your solution explorer, but will be included in the output directory.

Picked up on this trick here: http://blogs.msdn.com/b/shawnhar/archive/2007/06/06/wildcard-content-using-msbuild.aspx


I believe @Dmytrii gets it right on one hand - you want to use the "link" feature.

However, he's only partly correct when saying you can't link to a directory tree. While this is, indeed, true when trying to add the links using Visual Studio's GUI, MSBuild supports this.

If you want to preserve the directory structure, just add the %(RecursiveDir) tag to your <link> node:

<Content Include="..\..\MyContentFiles\**\*.*">
  <Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

The page MSBuild Well-known Item Metadata goes into more detail on the metadata you can access.


The following, which you would add to the bottom of your project file, will copy your content files maintaining the directory structure in a after build event to the target directory $(TargetDirectory) of your build (typically $(MSBuildProjectDirectory)\bin\Debug ).

<ItemGroup>
    <ExtraContent Include="$(MSBuildProjectDirectory)\..\..\MyContentFiles\**" />
</ItemGroup>

<Target Name="AfterBuild">
    <Copy 
        SourceFiles="@(ExtraContent)" 
        DestinationFiles="@(ExtraContent->'$(TargetDir)\%(RecursiveDir)%(Filename)%(Extension)')" 
        SkipUnchangedFiles="true" />
</Target>

If these files needed to go in a directory named MyContentFiles, you could add this before the copy:

<MakeDir Directories="$(TargetDir)\MyContentFiles" Condition=" !Exists('$(TargetDir\MyContentFiles') " />

and change

<Copy 
            SourceFiles="@(ExtraContent)" 
            DestinationFiles="@(ExtraContent->'$(TargetDir)\%(RecursiveDir)%(Filename)%(Extension)')" 
            SkipUnchangedFiles="true" />

To

<Copy 
            SourceFiles="@(ExtraContent)" 
            DestinationFiles="@(ExtraContent->'$(TargetDir)\MyContentFiles\%(RecursiveDir)%(Filename)%(Extension)')" 
            SkipUnchangedFiles="true" />

Tags:

Msbuild

Csproj