Visual Studio "Добавить как ссылку" не работает во время отладки
Я использую Visual Studio 2010 для поддержки около 40 различных веб-приложений, которые размещаются на одном и том же веб-сайте после развертывания. Эти проекты находятся в одном и том же решении, но размещаются в разных проектах, поскольку каждый из них делает разные вещи.
Я пытаюсь поделиться файлами css/js среди различных проектов с помощью опции "Добавить как ссылку", чтобы я мог обновлять файлы css или js один раз и автоматически обновлять обновления в различных проектах без необходимости создавать и перераспределять каждый проект.
Проблема, с которой я сталкиваюсь, заключается в том, что когда я пытаюсь запустить проект локально на своем ПК для целей отладки, эти связанные файлы не работают. Я получаю файл не найден.
Моя мысль: Я предполагаю, что это связано с тем, что при работе приложений локальная структура папок различна. Мне любопытно, есть ли способ скопировать файлы в проект только при создании в режиме отладки и соответственно настроить относительные URL-адреса, чтобы я мог правильно протестировать приложение перед публикацией на нашем веб-сервере.
Спасибо,
Ответы
Ответ 1
Решение этой проблемы - копирование файлов содержимого (например, js, css или других), которые добавляются как ссылка во время каждой сборки. Есть несколько способов сделать это. Я могу советовать использовать цель MSBuild, которая может быть повторно использована различными проектами веб-приложений.
Итак, вы можете создать следующий файл (например, назвав его WebApplication.Extension.targets) со следующим содержимым:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Override the default target dependencies to -->
<!-- include the new CopyLinkedContentFiles target. -->
<PropertyGroup>
<BuildDependsOn>
CopyLinkedContentFiles;
$(BuildDependsOn);
</BuildDependsOn>
</PropertyGroup>
<!--
============================================================
CopyLinkedContentFiles
A new target to copy any linked content files into the
web application output folder.
NOTE: This is necessary even when '$(OutDir)' has not been redirected.
============================================================
-->
<Target Name="CopyLinkedContentFiles">
<!-- Remove any old copies of the files -->
<Delete Condition=" '%(Content.Link)' != '' AND Exists('$(WebProjectOutputDir)\%(Content.Link)') "
Files="$(WebProjectOutputDir)\%(Content.Link)" />
<!-- Copy linked content files recursively to the project folder -->
<Copy Condition=" '%(Content.Link)' != '' " SourceFiles="%(Content.Identity)"
DestinationFiles="$(WebProjectOutputDir)\%(Content.Link)" />
</Target>
</Project>
Затем добавьте эту цель в проект веб-приложения, поместив следующую строку в файл .csproj:
<Import Project="$(MSBuildProjectDirectory)[RelativePathToFile]\WebApplication.Extension.targets" />
В принципе вы можете добавить эту строку в файл .csproj после следующего:
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
После того, как эта проблема с файлами содержимого, добавленными как ссылка, должна быть разрешена.
Edit:
Чтобы выполнить следующую логику только при построении конфигурации отладки в MSBUILD, у вас есть возможность указать элемент Condition.
Например, для импорта указанного целевого объекта только для конфигурации отладки вы можете обновить оператор импорта до следующего:
<Import Project="$(MSBuildProjectDirectory)[RelativePathToFile]\WebApplication.Extension.targets" Condition=" '$(Configuration)' == 'Debug' "/>
Edit2:
Чтобы преодолеть эту проблему некоторое время назад, я создал пакет MSBuild.WebApplication.CopyContentLinkedFiles 'nuget. Этот пакет добавляет цель MsBuild, которая копирует все файлы содержимого, добавленные в качестве ссылки на папку проекта во время сборки.
Ответ 2
Решение о автоматической копировании всех связанных файлов содержимого в их "виртуальные" местоположения в каждой сборке с использованием MSBuild находится здесь:
http://mattperdeck.com/post/Copying-linked-content-files-at-each-build-using-MSBuild.aspx
Это гарантирует, что ваши связанные файлы будут доступны браузеру, когда вы нажмете F5.
Ответ 3
Его также можно решить, вставив следующий фрагмент в конец вашего .proj файла, который будет содержать связанные файлы
<Target Name="CopyLinkedContentFiles" BeforeTargets="Build">
<Copy SourceFiles="%(Content.Identity)"
DestinationFiles="%(Content.Link)"
SkipUnchangedFiles='true'
OverwriteReadOnlyFiles='true'
Condition="'%(Content.Link)' != ''" />
Ответ 4
Есть одна большая проблема с копированием связанных файлов в виртуальное место: если вы используете Go To Definition (Shift + F2) на ссылке JavaScript, которая указывает на один из связанных файлов, вы попадете на локально скопированный файл, а не связанный файл. Затем вы обязаны ошибиться при редактировании локальной версии, тем самым устраняя преимущества использования связанных файлов. Кроме того, это может вызвать проблемы с Intellisense.
Лучшее решение: вместо копирования связанных файлов в текущий каталог проекта вместе со связанными ссылками скопируйте их в папку "hiddenDebug" в этом каталоге (или любой каталог, который вы хотите, сохраняя его в том же каталоге, что упрощает для управления, а затем для управления путями во время отладки, как я объясню ниже).
Здесь, как скопировать файлы из вашего общего хранилища в папку "hiddenDebug" (добавить в исходный проект Post-Build):
Отдельный файл CSS
xcopy/Y "$ (ProjectDir) App_Themes\Theme1\Shared.css" "$ (SolutionDir) WebApp\App_Themes\Theme1\hiddenDebug \"
Каталог JavaScript
xcopy/Y/S "$ (ProjectDir) Скрипты" "$ (SolutionDir) WebApp\Scripts\Shared\hiddenDebug \"
Когда вы отлаживаете, вы можете динамически изменять исходные пути общих файлов, используя Response.Filter в Global.asax. Вот пример:
Класс фильтра ответов (в общем проекте)
Imports System.IO
Namespace Code
Public Class LinkedReferencesFilter
Inherits MemoryStream
Private ReadOnly outputStream As Stream = Nothing
Private ReadOnly _IsDevEnvironment As Boolean = False
Public Sub New(ByVal output As Stream, IsDevEnvironment As Boolean)
Me.outputStream = output
Me._IsDevEnvironment = IsDevEnvironment
End Sub
Public Overrides Sub Write(ByVal buffer As Byte(), ByVal offset As Integer, ByVal count As Integer)
' Convert the content in buffer to a string
Dim contentInBuffer As String = UTF8Encoding.UTF8.GetString(buffer)
If Me._IsDevEnvironment Then
contentInBuffer = contentInBuffer.Replace("<script src=""Scripts/Shared/", "<script src=""Scripts/Shared/hiddenDebug/")
contentInBuffer = contentInBuffer.Replace("/Scripts/Shared/", "/Scripts/Shared/hiddenDebug/")
contentInBuffer = contentInBuffer.Replace("/App_Themes/Theme1/Shared.css", "/App_Themes/Theme1/hiddenDebug/Shared.css")
End If
Me.outputStream.Write(UTF8Encoding.UTF8.GetBytes(contentInBuffer), offset, UTF8Encoding.UTF8.GetByteCount(contentInBuffer))
End Sub
End Class
End Namespace
Global.asax
Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
' Simulate internet latency on local browsing
If Request.IsLocal Then
System.Threading.Thread.Sleep(50)
End If
Dim currentRelativePath As String = Request.AppRelativeCurrentExecutionFilePath
If request__1.HttpMethod = "GET" Then
If currentRelativePath.EndsWith(".aspx") Then
Dim IsDevEnvironment As Boolean = False
//Use whatever method you want to determine whether your current environment is a development environment:
#If CONFIG = "Develop" Then
IsDevEnvironment = True
#End If
Response.Filter =
New Shared.Code.LinkedReferencesFilter(
output:=Response.Filter,
IsDevEnvironment:=IsDevEnvironment)
End If
End If
End Sub
Устранение неполадок: попробуйте разгрузить и перезагрузить проект связанными элементами. Если это не поможет, добавьте каталог hiddenDebug в свой проект. Я должен был это сделать, но потом я смог удалить его позже. Это сложно... было бы неплохо, если бы Microsoft отполировала эту функцию, но сейчас я настроен.
Если вы не знали: при публикации своего веб-приложения исходные (связанные) файлы автоматически копируются в цель публикации. Как только это настроено, вы можете забыть об этом. Лучшая часть - вы не потеряете Intellisense или быструю навигацию.
После перехода на TypeScript большинство проблем с ссылками на файлы в файлах будут упрощены или устранены (я надеюсь на простой кросс-проект, например, что доступно для других управляемых языков .NET, но, возможно, такая функциональность).
Пожалуйста, дайте мне знать, работает ли это для вас, или если у вас есть лучший способ.
Ответ 5
Пакет Maxim NuGet великолепен! Я использую это в течение многих лет.
Единственная проблема, с которой я столкнулся - это то, что я получаю много предупреждений о пропущенных ссылках на такие вещи, как "System.Object", "System.Boolean", "Kendo" и т.д. В моих представлениях .cshtml. Если вы добавляете операторы @using, они не помогают, и фактически вы получаете предупреждение, что они не нужны. Это не мешает приложению компилироваться и запускаться, но мне бы хотелось, чтобы было какое-то решение. Я не нашел ни одного.