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

17

В Visual Studio вы можете сделать Add - & gt; 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? Если да, то как я могу сказать «копировать оригиналы всех связанных файлов в их целевой каталог?

    
задан nl-x 19.03.2013 в 17:59
источник
  • Ваше «решение» звучит невероятно запутанным и кошмаром для контроля источника. –  Sam Harwell 19.03.2013 в 18:11
  • @ 280Z28 Как общие файлы являются кошмаром для источника управления? Они копируются при сборке в выходной каталог, который не хранится в исходном элементе управления. –  Alexander Manekovskiy 19.03.2013 в 18:15
  • «Сбивание с толку» является субъективным. Однако это не влияет на контроль источника, поскольку OP не пытается проверить копии физического файла. Они представляют собой артефакт сборки, который просто находится в каталоге проекта. –  dss539 19.03.2013 в 18:28
  • @ 280Z28 Это совсем не сбивает с толку. Это ИМХО, так как это должно было быть реализовано VS. Либо в том, что я предлагаю, либо путем жесткой привязки файлов на уровне файловой системы (например, sym-ссылки в Linux). Я нахожу это поведение Visual Studio неутешительным и вводящим в заблуждение. Поскольку вы видите файл в Visual Studio, но он еще не существует. И, как сказано в DSS, контроль источника не будет проблемой, так как он добавит только физические файлы. Связанные файлы существуют только в csproj. –  nl-x 19.03.2013 в 18:51
  • @AlexanderManekovskiy Он не просит скопировать их в выходную папку. Он просит теневое копирование их в исходную папку. Копирование общих файлов в выходные папки будет простым, понятным и совсем не запутанным. –  Sam Harwell 19.03.2013 в 20:21

4 ответа

15

Вероятно, вы должны использовать функции 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" /> .

    
ответ дан dss539 19.03.2013 в 18:25
источник
  • 3 вопроса: (1) Мне не нужны временные метки или о том, что является более новым. Я рад видеть, что оригинал связанного элемента будет скопирован в каталог проекта на каждой сборке. Могу ли я просто пропускать входы и выходы? (2) @ (Нет) кажется странным массивом элементов связанных имен. Действительно ли он используется только для связанных элементов? Или может ли этот массив хранить и другие файлы / файлы? (3) Оригинал связанных файлов находится в DLL-проекте с именем «common», на который ссылаются все остальные проекты. Как уменьшить избыточность, как указано в примечании? –  nl-x 19.03.2013 в 19:07
  • Ответы 1) да, вы можете пропустить входы / выходы, это просто оптимизация 2) «Нет» - это имя, потому что инструмент, запущенный на них, «None» ... Файлы csharp добавляются как «Компилировать», компилятор работает на них. Вы можете увидеть элемент «Нет» в своем собственном файле csproj, если вы его ищете. 3) Я отредактирую свой ответ, чтобы объяснить, как это сделать. –  dss539 19.03.2013 в 19:30
  • (1) ok. (2) ой, поэтому я должен бояться других файлов, чем Связанные файлы, чтобы также скопировать? Извините, что вы все еще не понимаете полностью. (3) Круто! Благодаря! –  nl-x 19.03.2013 в 19:39
  • @ nl-x 2) да, очень бойтесь этого! Я отредактирую еще один подход, который будет более безопасным –  dss539 19.03.2013 в 19:53
  • Отредактированная версия не полагается на то, что вы уже связали конфигурацию. Как вы заметили, могут быть связанные файлы, которые вы не хотите копировать. Если вы действительно хотите скопировать все связанные файлы, вы можете вернуться к использованию группы «Нет», так как это группа VS размещает их. –  dss539 19.03.2013 в 20:31
Показать остальные комментарии
24

У меня были некоторые проблемы с ответ dss539 (протестирован vs2010). Во-первых, дубликаты появились в обозревателе решений для каждого сопоставленного файла. Во-вторых, '%link' не является аксессуаром свойства, это сама строка, и она всегда не равна пустой строке '' , поэтому каждый файл с действием None build был сопоставлен, дублирован и скопирован при сборке. В-третьих, связанные файлы копируются в корневой каталог проекта, но мне нужны файлы для копирования, где размещаются ссылки. Поэтому я внесла некоторые изменения:

<Target Name="CopyLinkedFiles" BeforeTargets="Build">
  <ItemGroup>
    <LinkedItem Include="@(Content)" Condition="%(Content.Link) != ''" />
  </ItemGroup>
  <Copy SourceFiles="@(LinkedItem)" DestinationFiles="%(LinkedItem.Link)"/> 
</Target>

LinkedItem больше не дублирует элементы в проводнике решений. Чтобы скопировать ссылку, вам необходимо установить действие Content build.

    
ответ дан lorond 02.07.2013 в 16:59
источник
  • звучит хорошо. +1 –  dss539 02.01.2014 в 20:03
  • VS 2013 с обновленным 4 тестированием –  Ahmed Alejo 23.02.2015 в 17:53
  • Это, похоже, работает очень хорошо. Следует отметить, что если вы используете это для совместного просмотра MVC, ваш «общий» проект должен быть проектом MVC, а не фактическим типом «Общий проект», вы потеряете поддержку intellisense. –  user2880616 07.05.2016 в 01:26
1

Щелкните правой кнопкой мыши связанный файл конфигурации, выберите свойства, измените Copy to Output Directory с Never на Copy always .

    
ответ дан Michael Sallmen 19.03.2013 в 18:12
источник
  • Я не думаю, что это действительно отвечает на его вопрос, потому что OP не хочет файл в выходном каталоге, а скорее в каталоге проекта. –  dss539 19.03.2013 в 18:26
  • Это действительно просто помещает файл в каталог bin. Не то, что я хочу. Код до сих пор ломается при отладке во время разработки, так как файл не существует, где исследователь решений показывает, что файл существует. –  nl-x 19.03.2013 в 18:32
  • Извините. Совершенно непонятно. –  Michael Sallmen 20.03.2013 в 14:49
0

Вы можете создавать события предварительной и последующей сборки в Visual Studio.

Выберите проект, щелкните правой кнопкой мыши, свойства, события сборки.

Для предварительной сборки -

copy /y "$(LocationOfShared.Config)Shared.config\" "$(TargetDir)"

Для пост-сборки

cd $(TargetDir)
del shared.config

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

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

    
ответ дан Alexander Matusiak 19.03.2013 в 18:13
источник
  • Другие ответы, похоже, не помогают мне. Итак, давайте посмотрим, что вы делаете. Во-первых, я вижу, что вы явно называете «Shared.config». Я бы хотел этого избежать. Мой вопрос был / «как я могу сказать» копировать оригиналы всех связанных файлов в их целевой каталог » –  nl-x 19.03.2013 в 18:35
  • @ nl-x Возможно, вы захотите взглянуть на мой ответ. Я уверен, что он делает именно то, что вы хотите. ;) –  dss539 19.03.2013 в 18:38
  • @Alexander Ow, и, кстати, вы можете пропустить часть сборки сообщения, так как я хочу, чтобы физический файл сохранялся в процессе отладки (который начинается после завершения пост-сборки). Фактически, я не хочу, чтобы этот физический файл вообще был удален. –  nl-x 19.03.2013 в 18:41
  • @ dss539 ваш ответ был невидим только сейчас ... Я сейчас смотрю на него. –  nl-x 19.03.2013 в 18:45
  • Кажется, вы хотите скопировать файл в местоположение, не указывая, куда идет файл. Я не думаю, что вы можете уйти от того, чтобы сказать, где, но есть способы сфабриковать файл, который скопирован. Если у вас будет фактический файл, присутствующий в этих местах, зачем беспокоиться о ссылке на файл? Просто используйте событие pre-build, чтобы скопировать «главный» файл конфигурации во все проекты / местоположения из его собственного каталога, чтобы скрыть то, что именно копируется. –  Alexander Matusiak 19.03.2013 в 19:21