Подтвердить что ты не робот

Visual Studio "Добавить как ссылку" не работает во время отладки

Я использую Visual Studio 2010 для поддержки около 40 различных веб-приложений, которые размещаются на одном и том же веб-сайте после развертывания. Эти проекты находятся в одном и том же решении, но размещаются в разных проектах, поскольку каждый из них делает разные вещи.

Я пытаюсь поделиться файлами css/js среди различных проектов с помощью опции "Добавить как ссылку", чтобы я мог обновлять файлы css или js один раз и автоматически обновлять обновления в различных проектах без необходимости создавать и перераспределять каждый проект.

Проблема, с которой я сталкиваюсь, заключается в том, что когда я пытаюсь запустить проект локально на своем ПК для целей отладки, эти связанные файлы не работают. Я получаю файл не найден.

Моя мысль: Я предполагаю, что это связано с тем, что при работе приложений локальная структура папок различна. Мне любопытно, есть ли способ скопировать файлы в проект только при создании в режиме отладки и соответственно настроить относительные URL-адреса, чтобы я мог правильно протестировать приложение перед публикацией на нашем веб-сервере.

Спасибо,

4b9b3361

Ответ 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, они не помогают, и фактически вы получаете предупреждение, что они не нужны. Это не мешает приложению компилироваться и запускаться, но мне бы хотелось, чтобы было какое-то решение. Я не нашел ни одного.