Связанные файлы Visual Studio не существуют
В Visual Studio вы можете сделать Add
→ Existing Item
, а затем Add as Link
с помощью кнопки Add
.
Это здорово. Это позволит вам добавить файл из другого проекта, и редактирование файла также редактирует его в исходном проекте.
Я хотел бы использовать эту функцию, чтобы иметь файл конфигурации (с именем Shared.config) во всех проектах в одном решении. И этот файл всегда будет таким же.
решение
|
| - проект 1
|
- Shared.config [физическое]
| - проект 2
|
- Shared.config [связанный]
После публикации файл действительно попадает во все опубликованные проекты, поэтому проблем нет.
Но перед публикацией (во время разработки на сборке) связанный файл на самом деле не существует. Попытка увидеть файл в проводнике Windows доказывает, что файл отсутствует в каталоге проекта. Visual Studio только заставляет его выглядеть так, как будто он существует в проводнике решений.
(Хотя при сборке связанные элементы, вероятно, скопированы в каталог bin
, но я не хочу использовать/получать доступ к файлам из каталога bin
.)
Теперь это дает проблемы с курса. Попытка распечатать System.IO.File.ReadAllText(HttpContext.Current.Server.MapPath("Shared.config"))
завершится с ошибкой до того, как проект будет опубликован, из-за того, что Shared.config еще не существует в корневом каталоге проекта.
Что я хотел бы сделать, и где мне нужна ваша помощь:
- Я бы хотел, чтобы ON BUILD скопировал все связанные файлы из их исходного местоположения в целевое местоположение.
Это сделает визуальную студию связанным файлом и копией оригинала, чтобы существовать как в том же каталоге с тем же именем.
Обычно VS не позволит вам создать связанный элемент в каталоге, если этот каталог уже содержит файл с тем же именем.
Но, я тестировал, сначала создав связанный элемент; затем с помощью проводника Windows скопируйте исходный файл в целевой каталог и посмотрите, как работает Visual Studio. Исследователь решений просто скрывает физический файл и показывает связанный элемент вместо него. (Даже если вы нажмете Show all files
в проводнике решений.)
решение
|
| - проект 1
|
- Shared.config [физическое]
| - проект 2
|
- Shared.config [связанный]
|
- Shared.config [физический, скопированный здесь во время сборки, невидимый в Solution explorer]
Это именно то, что я хочу! При попытке отредактировать файл Visual Studio откроет "связанный элемент". И при сборке физический файл будет скопирован в целевой каталог, чтобы он существовал для кода, который пытается получить к нему доступ.
Теперь, как мне это сделать?
Должно ли это быть сделано с событиями Build? Если да, то как я могу сказать "копировать оригиналы всех связанных файлов в их целевой каталог?
Ответы
Ответ 1
Вероятно, вы должны использовать функции MSBuild для реализации этого.
Отредактируйте файл csproj
(в Visual Studio щелкните правой кнопкой мыши проект и выгрузите его, затем щелкните правой кнопкой мыши и отредактируйте)
Прокрутите вниз, и вы должны найти эту строку.
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
Сразу после этой строки добавьте эти строки.
<ItemGroup>
<LinkedItem Include="@(None)" Condition="'%Link' != ''" />
</ItemGroup>
<Target Name="CopyLinkedFiles" BeforeTargets="Build" Inputs="@(LinkedItem)" Outputs="@(LinkedItem->'%(Filename)%(Extension)')">
<Copy SourceFiles="@(LinkedItem)" DestinationFolder="$(MSBuildProjectDirectory)" />
</Target>
Теперь каждый раз, когда вы создаете, прямо перед действием сборки MSBuild копирует все связанные файлы.
Объяснение
ItemGroup
содержит мой "массив" с именем "LinkedItem". Я генерирую этот массив, добавляя только элементы "Нет", которые содержат свойство ссылки.
Target
- это концепция MSBuild. Вы можете думать об этом как о конкретном этапе построения. Я назвал этот этап "CopyLinkedFiles", но вы можете назвать его чем угодно.
BeforeTargets
- это директива, которая сообщает MSBuild о запуске действия до указанной фазы. Здесь я решил запустить "CopyLinkedFiles" перед фазой "Build".
Inputs
- параметр оптимизации. Он используется для ускорения строительства путем пропуска копии, если это не необходимо. Вы можете игнорировать этот параметр, если вам все равно. MSBuild сравнивает Inputs
с ожидаемой временной меткой Outputs
, чтобы увидеть, нужно ли ее выполнять.
Copy
- это задача MSBuild, которая принимает файл для копирования и вывода в указанную папку.
Сокращение резервирования
Вы можете вставить это в каждый файл .csproj, или вы можете поместить его в центральный .proj и вставить его в файлы csproj. К сожалению, независимо от того, что вы делаете, вам придется редактировать каждый .csproj как минимум 1 раз.: (
Создайте файл в общем вызове проекта WhateverNameYouLike.proj
Поместите это содержимое в файл.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- paste the previously shown code here -->
<!-- you can save yourself some hassle by linking the config file here, but if you really enjoy adding the file as a link to every project, you can skip this line -->
<None Include="..\Common\Shared.config">
<Link>Shared.config</Link>
</None>
</Project>
Теперь раздражающая часть:
В каждом .csproj вам нужно будет добавить строку типа <Import Project="..\Common\WhateverNameYouLike.proj" />
вероятно, в конце перед закрывающим тегом </Project>
.
Ответ 2
У меня были некоторые проблемы с ответ dss539 (протестирован в vs2010). Во-первых, дубликаты появились в обозревателе решений для каждого сопоставленного файла. Во-вторых, '%link'
не является аксессуаром для свойства, он строит сам и всегда не равен пустой строке ''
, поэтому каждый файл с действием сборки None
был сопоставлен, дублирован и скопирован при сборке. В-третьих, связанные файлы копируются в корневой каталог проекта, но мне нужны файлы для копирования, где размещаются ссылки. Поэтому я внесла некоторые изменения:
<Target Name="CopyLinkedFiles" BeforeTargets="Build">
<ItemGroup>
<LinkedItem Include="@(Content)" Condition="%(Content.Link) != ''" />
</ItemGroup>
<Copy SourceFiles="@(LinkedItem)" DestinationFiles="%(LinkedItem.Link)"/>
</Target>
LinkedItem
больше не дублирует элементы в проводнике решений. Чтобы сделать ссылку для копирования, вам нужно установить Content
действие сборки.
Ответ 3
Щелкните правой кнопкой мыши связанный файл конфигурации, выберите свойства, измените Copy to Output Directory
с Never
на Copy always
.
Ответ 4
Вы можете создавать события предварительной и последующей сборки в Visual Studio.
Выберите проект, щелкните правой кнопкой мыши, свойства, события сборки.
Для предварительной сборки -
copy /y "$(LocationOfShared.Config)Shared.config\" "$(TargetDir)"
Для пост-сборки
cd $(TargetDir)
del shared.config
Очевидно, вам нужно будет поиграть с фактическими местоположениями, которые будут возвращены, но вы получите эту идею.
Изменить - приведенные выше ответы проще и понятнее, но это должно работать как круглый способ сделать это.