Be Careful When Copying Visual Studio Projects
Project GUIDs Uniquely Identify Projects
You might not be aware of it, but Visual Studio projects have additional identity beyond their project file name and path. Each one of them contains a GUID value which should by definition be unique in normal circumstances. The troubles begin, when you create a copy of a project by copying its folder and renaming the files.
Visual Studio uses project GUIDs to identify different project files and their dependencies in a solution file, as well as for references between projects inside a single solution file. For this to work, it needs all project GUIDs to be unique inside a solution file. When you add an existing project to the solution file, it verifies its project GUID and modifies it, if there is already a project with the same GUID in the solution. In simple scenarios this is enough to ensure consistency. If the same project is included in multiple solutions, Visual Studio might start to misbehave.
Making Visual Studio Confused
We'll start by creating 2 different solutions, each one containing a console application, referencing a class library:
Instead of creating ClassLibrary2
as a new project in Visual Studio, we will copy and rename ClassLibrary1
, and add it to the second solution. Although this will cause ClassLibrary1
and ClassLibrary2
to have the same project GUID, Visual Studio will keep them unchanged and won't complain because inside each solution the two projects have distinct project GUIDs.
In the next step we will add ClassLibrary2
to the first solution and also add it as a reference to ConsoleApplication1
:
This will already cause an inconsistency: the first solution will change the project GUID for ClassLibrary2
and use the new value in both the solution file and the ConsoleApplication1
project file to reference the library. ConsoleApplication2
will keep referencing the same library using its old project GUID. As a consequence the project GUID in the ClassLibrary2
project file will keep changing, depending on the last solution it was open with. Still, apart from phantom changes in source control, no other issues will arise yet.
To make matters worse, we can add ConsoleApplication2
to the first solution as well. This will brake Visual Studio in several ways:
The
ClassLibrary2
reference properties forConsoleApplication2
project will incorrectly point toClassLibrary1
, although it will still show up asClassLibrary2
in Solution Explorer. Obviously this functionality depends on the project GUID values. Fortunately this doesn't affect the build. MSBuild depends on filenames and still works correctly.The Project Dependencies window will also incorrectly show
ConsoleApplication2
depending onClassLibrary1
instead onClassLibrary2
. Since this information is used to define the project build order and restrict adding of project references in order to prevent circular dependencies, the consequences are quite dire. E.g. I can add a reference toConsoleApplication2
fromClassLibrary2
, creating a circular dependency. The new build order will causeClassLibrary2
to be built beforeConsoleApplication2
, although the latter requires the former for the build to succeed, hence the build will fail.
Avoid Duplicate Project GUIDs
I am aware that this a contrived example that could hardly happen in a real life scenario. However, when a team is working on a product consisting of dozens or even hundreds of projects, included in multiple different solution files for different development tasks, such situations can actually occur, if creating similar projects by copying existing ones becomes a habit. Trust me, I have encountered it. Troubleshooting wasn't easy and took some time.
Therefore, if you have a requirement for creating multiple similar projects, make sure you prevent duplicate project GUIDs from the start:
- I recommend you create a dedicated project template and distribute it to your developers. In simple scenarios the Export Template wizard can be all you need.
- Alternatively, you can create a new project based on one of Visual Studio built-in templates, followed by copying your specific files into it and including it in the project.
- If you still think, you need to copy the projects, you should add the copied project to the solution containing the original project and at least temporarily reference it from one of the other projects. This will ensure that the copied project will get a new unique project GUID value.
Having discipline from the start can save you a lot of time in the long run.