Включая файлы содержимого в.csproj, находящиеся вне конуса проекта
У меня есть проект на C#, скажем, MyProject.csproj, расположенный в "C:\Projects\MyProject\". У меня также есть файлы, которые я хочу скопировать в выходной каталог этого проекта. Но файлы находятся по адресу "C:\MyContentFiles\", т.е. они НЕ находятся внутри конуса проекта. В этом каталоге также есть подкаталоги. Содержимое каталога не управляется. Следовательно, я должен включить все, что находится под ним.
Когда я включаю их как "Контент" в проект, они копируются, но структура каталогов теряется. Я сделал что-то вроде этого:
<Content Include="..\..\MyContentFiles\**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
Как мне рекурсивно скопировать эти файлы / каталоги в выходной каталог проекта с сохранением структуры каталогов?
7 ответов
Вам необходимо добавить файл в виде ссылки:
- Щелкните правой кнопкой мыши по проекту в VS.
- Добавить -> Существующий элемент...
- Найдите файл.
- Выберите его и.
- Добавить как ссылку (выпадающий в кнопке Добавить в диалоговом окне).
- Откройте свойства файла и установите "Копировать в выходной каталог" в "Копировать всегда".
НО Вы не можете сделать это для дерева каталогов.
Вместо этого вам нужно написать задачу пост-сборки для этого. Это образец, на который вы будете смотреть.
Я считаю, что @Dmytrii понимает это правильно с одной стороны - вы хотите использовать функцию "ссылка".
Тем не менее, он только частично прав, когда говорит, что вы не можете ссылаться на дерево каталогов. Хотя это действительно так при попытке добавить ссылки с помощью графического интерфейса Visual Studio, MSBuild поддерживает это.
Если вы хотите сохранить структуру каталогов, просто добавьте %(RecursiveDir)
тег к вашему <link>
узел:
<Content Include="..\..\MyContentFiles\**\*.*">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
На странице MSBuild Metadata "Известный элемент" более подробно рассматриваются метаданные, к которым вы можете получить доступ.
Ответ 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
Следующее, которое вы бы добавили в конец вашего файла проекта, скопирует ваши файлы содержимого, сохраняя структуру каталога в событии после сборки, в целевой каталог $(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" />
Чтобы включить файлы в папку для проекта.NET Core,
<ItemGroup>
<None Update="..\..\MyContentFiles\**\*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
И свойство элементов "Копировать в выходной каталог" будет "Копировать, если новее":
Я думаю
<Content Include="..\..\MyContentFiles\**\*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
Достаточно, так как вы хотите, чтобы все в этой папке и подпапках
Чтобы игнорировать файл в проекте.Net Core:
<ItemGroup>
<Content Include="appsettings.local.json">
<CopyToOutputDirectory Condition="Exists('appsettings.local.json')">PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>