Включение файлов содержимого в .csproj, находящихся вне конуса проекта


85

У меня есть проект C #, скажем, MyProject.csproj, расположенный в «C: \ Projects \ MyProject \». У меня также есть файлы, которые я хочу скопировать в выходной каталог этого проекта. Но файлы находятся в расположении «C: \ MyContentFiles \», то есть они НЕ находятся в конусе проекта. В этом каталоге также есть подкаталоги. Содержание каталога не управляется. Следовательно, я должен включить все, что находится под ним.

Когда я включаю их в проект как «Контент», они копируются, но структура каталогов теряется. Я сделал что-то вроде этого: -

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

Как мне рекурсивно скопировать эти файлы / каталоги в выходной каталог проекта с сохранением структуры каталогов?

Ответы:


55

Вам нужно добавить файл в виде ссылки:

  1. Щелкните правой кнопкой мыши проект в VS.
  2. Добавить -> Существующий элемент ...
  3. Найдите файл.
  4. Выберите его и.
  5. Добавить как ссылку (раскрывающийся список на кнопке «Добавить» в диалоговом окне).
  6. Откройте свойства файла и установите «Копировать в выходной каталог» на «Всегда копировать».

НО Вы не можете сделать это для дерева каталогов.
Вместо этого вам нужно написать для этого задачу после сборки. Это образец , на который вы обратите внимание.


8
Как указано в этом ответе , «Вы не можете сделать это для дерева каталогов». утверждение не соответствует действительности.
Mandark,

161

Я считаю, что @Dmytrii правильно понимает это с одной стороны - вы хотите использовать функцию «ссылки».

Однако он прав лишь отчасти, когда говорит, что вы не можете ссылаться на дерево каталогов. Хотя это действительно так, когда вы пытаетесь добавить ссылки с помощью графического интерфейса Visual Studio, MSBuild поддерживает это.

Если вы хотите сохранить структуру каталогов, просто добавьте %(RecursiveDir)тег в свой <link>узел:

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

На странице « Метаданные хорошо известных элементов MSBuild» более подробно описаны доступные вам метаданные.


1
1) Что произойдет, если файл будет удален из хранилища общих ресурсов? Не похоже, что он будет удален из каталога решений. 2) Есть ли способ заставить Visual Studio удалить эти файлы из $ (SolutionDir) после завершения запуска. Если оставить их там, это может сбить с толку других разработчиков.
Adam

@Adam См. Мой ответ ниже
Робин ван дер Кнаап

8
Я потерпел крушение в пустыне с небольшим количеством еды, воды и сильной потребностью в общении, поэтому я считаю этот ответ полезным. Следуя этим инструкциям, я смог создать полностью функциональный ИИ, который теперь заменил все человеческие потребности, которые когда-то преследовали меня здесь в пустыне. Спасибо, Мандарк!
deepelement

1
@Vijay см. Мою правку, вам нужно <Content Include="..\..\MyContentFiles\**\*.*">- обратите внимание на значок \*.*в конце пути.
CAD bloke

2
Не работает для проекта .NET Core на VS2017 (15.8.6).
zwcloud

29

Ответ 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
Вы можете добавить <Visible> true </Visible> к элементу Content, чтобы элементы отображались в обозревателе решений.
Майкл Бейкер

У меня все в порядке с доменом .proj
Джейсон Дюфэр

У меня это вообще не сработало, и я предполагаю, что это связано с тем, что сами элементы, которые нужно связать, были сгенерированы в событии перед сборкой.
Paul K

2
Не работает для проекта .NET Core на VS2017 (15.8.6).
zwcloud

11

Следующее, которое вы должны добавить в конец файла проекта, скопирует ваши файлы содержимого, поддерживающие структуру каталогов в событии после сборки, в целевой каталог $(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" />

Чтобы

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

1
Ваши преобразования имеют тип-o: @ (ExtraContent) -> '...') должен быть @ (ExtraContext -> '...'). В противном случае хороший ответ!
alexdej 06

@Todd 1) Что произойдет, если файл будет удален из хранилища MyContentFiles? Не похоже, что он будет удален из каталога решений. 2) Есть ли способ заставить Visual Studio удалить эти файлы из $ (SolutionDir) после завершения запуска. Оставив их там, вы можете запутать других разработчиков.
Adam

Это было то, что мне было нужно. Процесс проекта и сборки теперь работает должным образом, но файлы не публикуются с помощью приложения, щелкнувшего один раз. Какие-нибудь намеки на это?
Георг В.

3

Я думаю

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

Достаточно, так как вы хотите, чтобы все в этой папке и подпапках


2

Чтобы включить файлы в папку для проекта .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>

И свойство элементов «Копировать в выходной каталог» будет «Копировать, если новее»:
Копировать, если новее


-1

Чтобы игнорировать файл в проекте .Net Core:

<ItemGroup>
 <Content Include="appsettings.local.json">
   <CopyToOutputDirectory Condition="Exists('appsettings.local.json')">PreserveNewest</CopyToOutputDirectory>
 </Content>
</ItemGroup>
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.