There's one big problem with copying linked files to the virtual location: if you use Go To Definition (Shift + F2) on a JavaScript reference that points to one of the linked files, you'll be taken to the locally-copied file, NOT to the linked file. Then, you're bound to make the mistake of editing the local version, thus eliminating the benefits of using linked files. Additionally, that can cause problems with Intellisense.
A better solution: Instead of copying the linked files to the current project directory alongside the associated links, copy them to a "hiddenDebug" folder within that directory (or any directory you wish; keeping it in the same directory makes it easier to manage, and then to manipulate the paths during debug, as I'll explain below).
Here's how to copy the files from your shared repository to your "hiddenDebug" folder (add to your source project's Post-Build event):
Single CSS File
xcopy /Y "$(ProjectDir)App_Themes\Theme1\Shared.css" "$(SolutionDir)WebApp\App_Themes\Theme1\hiddenDebug\"
JavaScript directory
xcopy /Y /S "$(ProjectDir)Scripts" "$(SolutionDir)WebApp\Scripts\Shared\hiddenDebug\"
When you're debugging, you can dynamically alter the shared files' source paths using Response.Filter in Global.asax. Here's an example:
Response Filter Class (in Shared project)
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
Troubleshooting: Try unloading and reloading the project with linked items. If that doesn't help, add the hiddenDebug directory to your project. I had to do that, but then I was able to remove it later. It's finicky...it would be nice if Microsoft polished this feature, but I'm set for now.
In case you didn't know: when you publish your web application, the source (linked) files are automatically copied to the publish target. Once this is set up, you can forget about it. The best part is, you won't lose Intellisense or quick navigation.
After migrating to TypeScript, most JavaScript file reference challenges will be simplified or eliminated (I'm hoping for easy cross-project referencing like what's available for other managed .NET languages, but there may already be some workarounds to enable such functionality).
Please let me know whether it works for you, or if you have a better way.