Связанные файлы 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 еще не существует в корневом каталоге проекта.
Что я хотел бы сделать, и где мне нужна ваша помощь:
- Я хотел бы, чтобы при сборке скопировать все связанные файлы из исходного местоположения в целевое местоположение.
Это позволит Visual Studio иметь связанный файл и копию оригинала, которые существуют в одном каталоге с одним и тем же именем.
Обычно VS не позволяет вам создавать связанный элемент в каталоге, если этот каталог уже содержит файл с тем же именем.
Но я проверил, сначала создав связанный элемент; затем с помощью проводника Windows скопируйте исходный файл в каталог назначения и посмотрите, как Visual Studio работает нормально. Обозреватель решений просто скрывает физический файл и показывает связанный элемент вместо него.
(Даже если вы нажмете Show all files
в обозревателе решений.)
решение|
| - проект 1
|
- Shared.config [физический]
| - проект 2
|
- Shared.config [связанный]
|
- Shared.config [физический, скопирован здесь во время сборки, невидим для Solution Explorer]
Это именно то, что я хочу! При попытке отредактировать файл, Visual Studio откроет "связанный элемент". А при сборке физический файл будет скопирован в целевой каталог, поэтому он существует для кода, который пытается получить к нему доступ.
Теперь, как мне это сделать? Должно ли это быть сделано с событиями Build? Если да, то как мне сказать "скопировать оригиналы всех связанных файлов в их целевой каталог?
4 ответа
Возможно, вам следует использовать возможности 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>
закрывающий тег
У меня были некоторые проблемы с ответом 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
строить действие.
Щелкните правой кнопкой мыши связанный файл конфигурации, выберите свойства, измените Copy to Output Directory
от Never
в Copy always
,
Вы можете создавать события до и после сборки в Visual Studio.
Выберите проект, щелкните правой кнопкой мыши, свойства, построить события.
Для предварительной сборки -
copy /y "$(LocationOfShared.Config)Shared.config\" "$(TargetDir)"
Для пост сборки
cd $(TargetDir)
del shared.config
Очевидно, вам нужно поиграть с реальными местами, которые будут возвращены, но вы поняли идею.
Редактировать - приведенные выше ответы проще и понятнее, но это должно работать как обходной путь.