在.csproj中包含位于项目范围外的内容文件

107

我有一个C#项目,名为MyProject.csproj,位于"C:\Projects\MyProject\"。我还有一些文件,希望将它们复制到该项目的输出目录中。但是这些文件位于"C:\MyContentFiles\"位置,即它们不在项目范围内。该目录还包含子目录。目录内容未经管理,因此我必须包含其下的所有内容。

当我将它们作为“内容”包含在项目中时,它们会被复制,但目录结构会丢失。我尝试过类似以下方式:

<Content Include="..\..\MyContentFiles\**">
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

我应该如何递归地将这些文件/目录复制到项目的输出目录中,并保留目录结构?

7个回答

198

我认为@Dmytrii的一部分是正确的 - 您需要使用“link”功能。

然而,当他说您无法链接到目录树时,他只有部分正确。虽然在尝试使用Visual Studio的GUI添加链接时确实如此,但MSBuild支持此操作。

如果您希望保留目录结构,请在<link>节点中添加%(RecursiveDir)标记:

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

这个页面 MSBuild Well-known Item Metadata 更详细地介绍了您可以访问的元数据。


1
  1. 如果从共享资产存储中删除文件,会发生什么?看起来它不会从解决方案目录中删除。
  2. 有没有办法让Visual Studio在运行完成后从$(SolutionDir)中删除这些文件。留下它们可能会让其他开发人员感到困惑。
- Adam
@Adam 请看下面我的回答 - Robin van der Knaap
11
在荒野中缺乏食物和水,又渴望有伴侣的陪伴时,我发现这个答案很有帮助。按照这些指示,我成功地建立了一个完全可用的人工智能,取代了曾经在这里困扰我的所有人类需求。感谢Mandark! - deepelement
1
@Vijay,请看我的编辑,你需要 <Content Include="..\..\MyContentFiles\**\*.*"> - 注意路径末尾的 \*.* - CAD bloke
4
无法在VS2017(15.8.6)上为.NET Core项目工作。 - zwcloud
显示剩余7条评论

65
您需要将文件作为链接添加:
  1. 在VS中右键单击项目。
  2. 添加 -> 现有项...
  3. 找到该文件。
  4. 选择它并。
  5. 使用“添加”对话框中的下拉菜单将其添加为链接
  6. 打开文件属性,并将“复制到输出目录”设置为“始终复制”。

但是您不能为目录树执行此操作。
相反,您需要编写后构建任务。 这是一个示例,可以帮助您入门。


11
此回答所述,“你不能对目录树这样做”这个说法是不正确的。 - Mandark

36

Mandark的答案 将内容文件直接添加到解决方案中,这些文件将显示在解决方案资源管理器中。每当在原始目录中添加或删除文件时,Visual Studio不会自动检测到此更改。此外,每当在解决方案资源管理器中删除或添加文件时,项目文件都会被修改,并且所有文件都会单独包含,而不是只包含整个文件夹。

为了防止这种情况发生,您可以使用同样的方法,但是将其放入一个单独的项目文件中,然后导入它。

项目文件(例如include.proj)如下所示:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Content Include="..\..\MyContentFiles\**">
  <Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
在你自己的项目文件中,添加以下行。
<Import Project="include.proj" />

Visual Studio不会修改这个文件,只会在构建过程中添加文件作为内容。原始目录中的更改始终会被包含。这些文件不会显示在解决方案资源管理器中,但会包含在输出目录中。

在这里学到了这个技巧:http://blogs.msdn.com/b/shawnhar/archive/2007/06/06/wildcard-content-using-msbuild.aspx


1
由于某些原因,我使用.proj文件似乎无法使其工作,但是我能够使用.csproj文件使其工作。 - StriplingWarrior
6
您可以在Content元素中添加<Visible>true</Visible>,以使项目在解决方案资源管理器中显示。 - Michael Baker
我的只需要一个 .proj 就可以了。 - Jason Dufair
这对我完全没有用,我认为原因是要链接的项目本身是在预构建事件中生成的。 - Paul K
这也可以消除令人讨厌的“此文件在项目目录树中”错误 - 谢谢! - Rob
3
无法在VS2017(15.8.6)上为.NET Core项目工作。 - zwcloud

15

以下代码会在项目文件末尾添加,它将在"生成后事件"中复制您的内容文件,并将保留目录结构到构建的目标目录$(TargetDirectory) (通常为$(MSBuildProjectDirectory)\bin\Debug)。

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

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

如果这些文件需要放在名为MyContentFiles的目录中,您可以在复制之前添加以下内容:

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

并更改

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

1
你的转换有一个拼写错误:@(ExtraContent)->'...' 应该是 @(ExtraContext->'...')。除此之外,答案很好! - alexdej
@Todd 1) 如果从MyContentFiles存储中删除文件会发生什么?看起来它不会从Solution Dir中删除。2) 是否有办法让Visual Studio在运行完成后从$(SolutionDir)中删除这些文件。将它们留在那里可能会让其他开发人员感到困惑。 - Adam
这正是我所需要的。项目和构建过程现在按预期工作,但文件未与单击一次应用程序一起发布。有什么提示吗? - Georg W.

10

要在.NET Core项目中包含文件夹中的文件,

<!--Just files-->
<ItemGroup>
  <None Update="..\..\MyContentFiles\**\*.*">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>
<!--Content files-->
<ItemGroup>
  <Content Include="..\..\MyContentFiles\**\*.*" Link="MyContentFiles\%(RecursiveDir)%(Filename)%(Extension)">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </Content>
</ItemGroup>

而项目的属性"复制到输出目录"将会是"如果较新则复制":
如果较新则复制


5

我认为

<Content Include="..\..\MyContentFiles\**\*.*">
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

只需这样就可以了,因为您想要该文件夹及其子文件夹中的所有内容。


-1

在 .Net Core 项目中忽略文件的方法如下:

<ItemGroup>
 <Content Include="appsettings.local.json">
   <CopyToOutputDirectory Condition="Exists('appsettings.local.json')">PreserveNewest</CopyToOutputDirectory>
 </Content>
</ItemGroup>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接