Visual Studio Project Files

Summary

In this blog post I’m going to talk about Visual Studio’s proj file which is nothing more than an XML file used to keep track of the resources inside a project.

The Setup

Open your Visual Studio (I’m currently using VS 2012) and create a console application. If you have your solution explorer window open you should see something like this:

Now, let’s create a cs file in the solution and make an empty class. I just right-clicked on the project (ProjectFileBlogPost in this example) then selected “Add” then “Class”. Now click on your project to make sure it’s selected then go to your project menu (on the main menu bar) and select “Show All Files”. Right-click on your TestClass.cs file and select “Exclude From Project”. The file will turn white, indicating that it is not part of the project and will not be compiled with your solution.

If you’ve been working with Visual Studio for any length of time, you probably already know how all this works because you can copy a cs file from another project from Windows Explorer and then include it in your project to make it appear in the solution explorer. Now I’m going to show how the XML project file works.

The Project File

Now we’re going to use Visual Studio to edit the xml file. First, you need to close your console application (because it locks the file). Next you’ll need to go to the File menu and open a file (just a plain file, not a project). Once you open the file, VS will recognize it as an XML file and color code the text accordingly.

If you scroll through the XML, you’ll noticed that there are a bunch of ItemGroup sections. The one we’re interested in is one that contains a bunch of “Compile” nodes:

As you can see only the Program.cs file and the AssemblyInfo.cs files are in this group. If you copy the Program.cs node and change the file name to TestClass.cs and save this file, you’ll be able to open this project in VS and the TestClass.cs file will be included in the project.

If you delete any of these “Compile” nodes, then the file will no longer be included in the project by VS.

Folders

If your cs file is in a folder then the full path can be spelled out in the “Compile” node and the folder will be included in your project as well as the file. However, if you want an empty folder to be included in your project, you’ll need to add it to a different ItemGroup node set. These nodes are named Folder nodes:

If a folder node exists and there are references in the group of Compile nodes, VS will be OK with that, but it’s not necessary.

Manipulating The Project File

At this point, you probably have a program that generates some sort of C# files and you want those files to be automatically added to some utility project. It’s best to use the XmlDocument object to manipulate the data in the project file to add any of your C# files and/or directories. Text parsing can be a nightmare. You’ll need to use a name space to make it work:

XmlDocument doc = new XmlDocument();
doc.Load(projectFileName);

var nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("a", 
        "http://schemas.microsoft.com/developer/msbuild/2003");
XmlNodeList itemGroupNodes = doc.SelectNodes(
        "//a:Project/a:ItemGroup", nsmgr);

// add and delete nodes here

doc.Save(projectFileName);

You can spin through all the ItemGroup nodes and look for child nodes that have the name “Folder” or “Compile”, then add Folder or Compile nodes as desired. You’ll have to account for the possibility that there are no ItemGroup nodes with Folder or Compile nodes in them. You can use something like this to find the proper ItemGroup nodes:

foreach (XmlNode itemGroupNode in itemGroupNodes)
{
    XmlNodeList childNodes = itemGroupNode.ChildNodes;

    foreach (XmlNode childNode in childNodes)
    {
        if (childNode.Name == "Folder")
        {
            // your code here
        }
    }
}

In order to append a new node to your Folder node, you can do something like this:

XmlNode folderNode = doc.CreateNode(XmlNodeType.Element, 
     "Folder", 
     "http://schemas.microsoft.com/developer/msbuild/2003");
XmlAttribute xKey = doc.CreateAttribute("Include");
xKey.Value = "TestFolder";
folderNode.Attributes.Append(xKey);
itemGroupNode.AppendChild(folderNode);

Another thing to note: You should check the namespace name in the top of your project file. I copied that text into these sample snippets, but I’m using VS 2012 and there is no guarantee that the namespace URL won’t change for newer versions of VS.

Leave a Reply