Связанные файлы Visual Studio не существуют

В Visual Studio вы можете сделать AddExisting 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

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

Изменить - приведенные выше ответы проще и понятнее, но это должно работать как круглый способ сделать это.