Sharing files with Visual Studio's linked files
A solution is to store the shared files in a central location, and then in Visual Studio add links to those files, rather than copying them. That way, Visual Studio always sees the latest version.
To create a link in Visual Studio:
- Right click on the directory where you want to add the link.
- Choose Add | Existing Item.
- In the file dialog, navigate to the directory with shared files and select the one you want.
- Open the drop down on the Add button (click the little down arrow) and choose Add As Link.
The shared file now appears in the Solution Explorer, with a "link" icon.
When you now edit a shared file, you'll find that the change is immediately visible in all web applications. If you keep the file in source control and you're using TFS rather than GIT, TFS will automatically check out the file when you change the file from any of the web applications.
Moreover, when you publish a web application, the shared files will be copied along with the other files of the site. Sweet!
Using an MSBuild target to physically copy the linked files
There is one problem though. When you hit F5 to debug the site, the browser can't find your linked shared files. This is because Visual Studio keeps a link to the shared file - it doesn't copy it to the directory where you placed the link in Solution Explorer.
The challenge now is to extend the build, so each time the project is built (by hitting F5 or otherwise), all linked files are copied to the directories where you placed the links. This way, you still automatically pick up changes to the shared files, while also making them available to the browser.
To see how this is going to work, we'll need to have a look at how Visual Studio stores file links:
- Add a link to a file to your project if you haven't already done so.
- Open the .csproj file with your favorite text editor (Notepad will do).
- Find the file that you linked to - search for its name.
You'll find that whilst most content files have entries like this:
<Content Include="Scripts\jsnlog_test.js" />
File links look like this:
In other words, their distinguishing feature is that they have a Link meta with the location where the file would have been had it been physically copied over.
This means that we can copy the linked files at each build by adding the following at the end of the .csproj file, just before the final </Project> tag:
<Target Name="CopyLinkedContentFiles" BeforeTargets="Build">
Condition="'%(Content.Link)' != ''" />
This target uses BeforeTargets to ensure it is executed each time a build happens, even when no files in the project need to be built.
The Copy task uses a Condition to filter out all items in the Content item group that do not have a Link meta. This way, the copy is only applied to links. To speed up the process, it sets SkipUnchangedFiles to true, so if a linked file has not been changed, it won't be copied.