Sharing Files Between Projects in Visual Studio

posted by matt on Monday, January 25, 2010

The Problem

This probably isn't a common situation, but there are arguable cases where you may want to share files between projects in a single solution. In my example, I had the following solution structure:

/Solution
/SharedControls
/Project1
/Project2
(etc)

In the SharedControls project, I had stylesheets, theme content, scripts, and some common user controls that both of the other projects were using. It wouldn't be too difficult to manually copy this content to each project, but it's an extra step to remember and to track updates to each file.

When I was working on this solution setup locally, I found an easy way to address this problem, courtesy of Scott Guthrie; start by following the tutorial here:

http://webproject.scottgu.com/CSharp/UserControls/UserControls.aspx

The summary of the tutorial above is to create a web application project: SharedControls. Then add SharedControls as a project reference in each of your other projects. After that, add a copy command line event to the Pre-Build event in each project to copy the shared files from the SharedControls project.

This is a great solution for a single developer, but it does have a few issues:

  • The build time is increased, especially if you are copying a lot of files.
  • Each file is copied when you  debug, build, or publish a project/solution. even if it is unchanged.
  • You have to make sure any changes in the shared files are made in the SharedControls project only.

Now, fast forward to my current team's implementation of Visual Studio Team Foundation Server. A solution like the one above was added into source control so that multiple developers could begin working on the projects. The first time someone tried to build a project, they received a failure message:

The command "copy "C:\Projects\Articles\Solution\SharedControls\Controls\*.ascx" "C:\Projects\Articles\Solution\Project2\Controls\"" exited with code 1.

The build operation was failing because of the pre-build event. When using TFS, your local workspace files are marked as read-only unless you have the file checked out, so the copy command is unable to overwrite the existing files, even with the force flag specified.

A Solution

I was able to address the build failures and also come up with a much better way to manage this type of setup in the process.

First, instead of copying the shared files to each project, you just set up linked files instead:

Add a reference in each project to the SharedControls project (just like in the original tutorial). Right click on the project file and select Add Reference:
image

Select the Projects tab and select the SharedControls project, and click OK:
image

In Visual Studio, right-click the Project folder or any folder in the project and select Add > Existing Item:
image

Navigate to the SharedControls project folder and select the file(s) you would like to link. Click the arrow next to the Add button and select Add As Link:
image

Now, any time you change the file from any project, all of the linked copies stay in sync. The linked file is just a reference to the copy in the SharedControls folder. If you publish your project now, you will also see that a physical copy of each linked file will be added to the target directory, this is exactly what we wanted!

Now, we're all set. except if you try to debug your project. more errors?!?

If you have linked control files, aspx pages, scripts, or images you will notice that all of them are missing when you start the project in debug mode. This is because the integrated development server points to the project folder, and the physical versions of the files no longer exist in your working project directory, even though they are part of the build.

So you need to make sure that a physical version of the file exists. Since Team Server no longer manages the project files that have been linked in each project, the copy operation should no longer fail.

I mentioned the limitations of Scott Guthrie's solution for copying files during pre-build. This is the script I used in place of his original:

xcopy "$(SolutionDir)SharedControls\Controls\*.ascx" "$(ProjectDir)Controls\" /D /Y
xcopy "$(SolutionDir)SharedControls\App_Themes\*" "$(ProjectDir)App_Themes\" /D /Y /S

So you still create physical copies in the development folder of each linked file, but they are no longer part of the project itself.

The /D flag will only copy the file from the shared projects folder if it is a more recent version than the one that already exists in the destination folder. The /Y option forces an overwrite if the file already exists. The /S option will perform a recursive copy operation.

Right-click on the Project and select Properties. Click on the Build Events tab on the left and add the xcopy command(s) to the Pre-build event command line field:
image

Now if you build your project again, you should be able to debug without any issues.

One final note: When you drag and drop a linked control to your page in design mode, it will show up in the source view like this:

<%@ Register src="../SharedControls/Controls/SampleControl.ascx" tagname="SampleControl"
tagprefix="uc1" %>

 

The src tag is referencing the path to the physical file; You just need to update this tag to reflect the control's  "location" in the current project:

<%@ Register src="Controls/SampleControl.ascx" tagname="SampleControl" tagprefix="uc1" %>

 

There are many different ways to manage shared content between projects, and this is one of the more basic approaches. If you are working under limited resources and cannot dedicate a user to creating control libraries, this is definitely an approach to consider. You can minimize duplication of work, and make sure that you are able to manage your projects in a consistent manner.

You can download a sample solution here to review how this is set up.

1 comment for “Sharing Files Between Projects in Visual Studio”

  1. Nicolas Posted Saturday, March 20, 2010 at 1:33:11 PM
    Gravatar of NicolasThanks for this article. In vb, build and buid events tabs are not displayed like in c#. 3 hours to find them under and other window.
    It works !

Post a comment