Click here to Skip to main content
13,250,883 members (48,130 online)
Click here to Skip to main content
Add your own
alternative version


100 bookmarked
Posted 17 Jun 2009

A Project Dependency Graph Utility for Visual Studio 2008

, 17 Jun 2009
Rate this:
Please Sign up or sign in to vote.
Review your project dependencies.




I recently wanted to look at the dependencies of a fairly large set of projects in a solution (not the one in the screenshot), and discovered that while there are apps/tools that do that, they are either Code Project articles for previous versions of Visual Studio or they create an unreadable smear of boxes and lines, because they were never designed to handle a solution with 50 or more projects. So, I decided to create a textual, treeview based browser of dependencies.

It's very simple, offering both a hierarchical view of project dependencies or a flattened list of dependencies, and also a tree-view showing projects that are dependencies of other projects (the right-hand side of the image above).


  • Will undoubtedly become obsolete with VS2010
  • Works only with C# projects (any other project type is not parsed)
  • Works only with VS2008 solution files

Hierarchical View of Project Dependencies

Note how the view is hierarchical, allowing you to drill into each project's dependencies.

Flattened View of Project Dependencies

In this view, the application drills into project dependencies for you and presents all unique dependencies in a flattened list:

Project's Dependency on Other Projects

You can also pick a project and find out what projects reference the selected project:

The Code

The code is really simple. Very little error checking and pretty much brute force implementation. The one annoying thing I discovered is that the solution file is not an XML document, whereas the project files (csproj) are. Makes one wonder.

Reading the Solution File

Basically, this involves a lot of string checking and processing, in which a dictionary of project names and project paths is created.

public class Solution
  protected Dictionary<string, string> projectPaths;

  public Dictionary<string, string> ProjectPaths 
    get { return projectPaths; }

  public Solution()
    projectPaths = new Dictionary<string, string>();

  // Example:
  // Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NumericKeypadComponent", 
  //   "NumericKeypadComponent\NumericKeypadComponent.csproj", 
  //   "{05D03020-4604-4CE9-8F99-E1D93ADEDF15}"
  // EndProject

  public void Read(string filename)
    StreamReader sr = new StreamReader(filename);
    string solPath = Path.GetDirectoryName(filename);

    while (!sr.EndOfStream)
      string line = sr.ReadLine();

      if (!String.IsNullOrEmpty(line))
        if (line.StartsWith("Project"))
          string projName = StringHelpers.Between(line, '=', ',');
          projName = projName.Replace('"', ' ').Trim();
          string projPath = StringHelpers.RightOf(line, ',');
          projPath = StringHelpers.Between(projPath, '"', '"');
          projPath = projPath.Replace('"', ' ').Trim();

          // virtual solution folders appear as projects but don't end with .csproj
          // gawd, imagine what happens if someone creates a foo.csproj 
          // virt. solution folder!
          if (projPath.EndsWith(".csproj"))
            // assume relative paths. Probably not a good assumption
            projPath = Path.Combine(solPath, projPath);

            // we don't allow projects with the same name, even if different paths.
            projectPaths.Add(projName, projPath);


Reading a Project File

Ah, an XML file! Woohoo! It took a while for me to realize that I needed to specify the XML namespace along with the element name. As in, several hours of fussing, pulling hair out, and finally stumbling across some documentation in MSDN that gave an example of using Elements with a namespace. Sigh.

Similar to the Solution class, this class builds a dictionary of referenced projects, where the key is the referenced project name and the value is the referenced project path.

public class Project
  protected Dictionary<string, string> referencedProjects;
  protected List<Project> dependencies;

  public string Name { get; set; }

  public Dictionary<string, string> ReferencedProjects
    get { return referencedProjects; }

  public List<Project> Dependencies
    get { return dependencies; }

  public Project()
    referencedProjects = new Dictionary<string, string>();
    dependencies = new List<Project>();

  // Example:
  // <Project ToolsVersion="3.5" DefaultTargets="Build" 
  // xmlns="">
  // <ItemGroup>
  // <ProjectReference Include="..\Cx.Attributes\Cx.Attributes.csproj">
  // <Project>{EFDBD81C-64BE-47F3-905E-7618B61BD224}</Project>
  // <Name>Cx.Attributes</Name>
  // </ProjectReference>

  public void Read(string filename)
    XDocument xdoc = XDocument.Load(filename);
    XNamespace ns = "";

    foreach (var projRef in from el in 
       xdoc.Root.Elements(ns + "ItemGroup").Elements(ns + "ProjectReference")
    select new
      Path = el.Attribute("Include").Value,
      Name = el.Element(ns + "Name").Value
      string projPath = Path.GetDirectoryName(filename);
      projPath = Path.Combine(projPath, projRef.Path);
      referencedProjects.Add(projRef.Name, projPath);

Parsing the Solution File

A separate method is used to put the solution and projects together into yet another dictionary, this time the key being the project name and the value being a Project instance. This method also populates the Dependencies collection in the Project class (yeah, that's really bad practice, I know).

protected Dictionary<string, Project> projects;

protected void ParseSolution(string filename)
  projects = new Dictionary<string, Project>();
  Solution sol = new Solution();

  foreach (KeyValuePair<string, string> kvp in sol.ProjectPaths)
    Project proj = new Project();
    proj.Name = kvp.Key;
    projects.Add(proj.Name, proj);

  foreach (KeyValuePair<string, Project> kvp in projects)
    foreach (string refProjName in kvp.Value.ReferencedProjects.Keys)
      Project refProject = projects[refProjName];

Populating the Dependency Graph

There are two ways of populating the dependency graph: hierarchical or flat. The code for both is similar--the big difference is that child nodes aren't being created. And another ugly kludge in the flattened implementation is how I search for assemblies already in the node collection. Yuck!

/// <summary>
/// Sets up initial project name and first level of dependencies.
/// From there, child dependencies are either added hierarchically or flattened.
/// </summary>
protected void PopulateNewLevel(TreeNode node, ICollection<Project> projects)
  List<string> nodeNames = new List<string>();

  foreach (Project p in projects)
    TreeNode tn = new TreeNode(p.Name);

    if (asTree)
      PopulateNewLevel(tn, p.Dependencies);
      // flatten the dependency hierarchy, removing duplicates
      PopulateSameLevel(tn, p.Dependencies);

protected void PopulateSameLevel(TreeNode node, ICollection<Project> projects)
  foreach (Project p in projects)
    bool found = false;

    foreach (TreeNode child in node.Nodes)
      if (child.Text == p.Name)
        found = true;

    if (!found)
      TreeNode tn = new TreeNode(p.Name);

    PopulateSameLevel(node, p.Dependencies);

Populating the "Is Dependency Of" Graph

Also straightforward, also has a kludge to remove duplicate project names.

protected void PopulateDependencyOfProjects(TreeNode node, ICollection<Project> projects)
  foreach (Project p in projects)
    TreeNode tn = new TreeNode(p.Name);

    foreach (Project pdep in projects)
      foreach (Project dep in pdep.Dependencies)
        if (p.Name == dep.Name)
          bool found = false;

          // the project pdep has a dependency on the project p.
          // p is a dependency of pdep
          foreach (TreeNode tnDep in tn.Nodes)
            if (tnDep.Text == pdep.Name)
              found = true;
          if (!found)
            TreeNode tn2 = new TreeNode(pdep.Name);


Hopefully someone will find this useful and maybe even build upon it! It was a short and fun to write application. One thing I'd like to add is sorting the project names.


6/17/2009 - Initial Version


  • Projects are now sorted alphabetically 
  • Added a synchronize option, which finds the project in the opposing tree, selects it, and opens the tree.  This is really useful to look at both project dependencies and dependencies of a project at the same time. 

7/5/2009 - Added rendering of graph using graphviz.  Thanks to Dmitri Nesteruk for making the original changes to this application and for making his rendering code public.



This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Marc Clifton
United States United States
Marc is the creator of two open source projects, MyXaml, a declarative (XML) instantiation engine and the Advanced Unit Testing framework, and Interacx, a commercial n-tier RAD application suite.  Visit his website,, where you will find many of his articles and his blog.

Marc lives in Philmont, NY.

You may also be interested in...

Comments and Discussions

QuestionVote 5 Pin
Matan Fihman9-Dec-13 4:00
memberMatan Fihman9-Dec-13 4:00 
AnswerRe: Vote 5 Pin
Marc Clifton9-Dec-13 4:06
protectorMarc Clifton9-Dec-13 4:06 
QuestionRuntime Error Pin
Member 86133661-Feb-12 8:00
memberMember 86133661-Feb-12 8:00 
AnswerRe: Runtime Error Pin
daiwuju5-Jun-12 3:55
memberdaiwuju5-Jun-12 3:55 
Generalsearching................... Pin
raj vaasu yadav27-Jan-12 19:55
memberraj vaasu yadav27-Jan-12 19:55 
GeneralMy vote of 5 Pin
Kanasz Robert1-Dec-11 3:47
memberKanasz Robert1-Dec-11 3:47 
This is really good article. In a couple of weeks I will use it in one of my projects.
Generalsimple to use javascript variant Pin
Member 35155522-Jan-11 16:59
memberMember 35155522-Jan-11 16:59 
GeneralGreat stuff Pin
bstabile31-May-10 10:22
memberbstabile31-May-10 10:22 
GeneralRe: Great stuff Pin
Marc Clifton31-May-10 10:25
protectorMarc Clifton31-May-10 10:25 
GeneralNice little tool! Pin
dgaudian11-Apr-10 22:37
memberdgaudian11-Apr-10 22:37 
GeneralRe: Nice little tool! Pin
Marc Clifton12-Apr-10 4:13
protectorMarc Clifton12-Apr-10 4:13 
QuestionDownload not Working ?? Pin
Bill Elsey13-Oct-09 4:20
memberBill Elsey13-Oct-09 4:20 
AnswerRe: Download not Working ?? Pin
Marc Clifton13-Oct-09 5:18
protectorMarc Clifton13-Oct-09 5:18 
GeneralBinding XDocument content to treeview Pin
mukhtharsal31-Jul-09 1:38
membermukhtharsal31-Jul-09 1:38 
GeneralThanks Pin
Johan Fourie12-Jul-09 18:44
memberJohan Fourie12-Jul-09 18:44 
GeneralRe: Thanks Pin
Marc Clifton13-Jul-09 5:04
protectorMarc Clifton13-Jul-09 5:04 
QuestionWhere is the graph? Pin
Dmitri Nesteruk27-Jun-09 21:43
memberDmitri Nesteruk27-Jun-09 21:43 
AnswerRe: Where is the graph? Pin
Marc Clifton28-Jun-09 10:22
protectorMarc Clifton28-Jun-09 10:22 
AnswerRe: Where is the graph? Pin
Dmitri Nesteruk28-Jun-09 10:34
memberDmitri Nesteruk28-Jun-09 10:34 
GeneralRe: Where is the graph? Pin
Marc Clifton28-Jun-09 10:38
protectorMarc Clifton28-Jun-09 10:38 
AnswerRe: Where is the graph? Pin
Dmitri Nesteruk28-Jun-09 10:50
memberDmitri Nesteruk28-Jun-09 10:50 
GeneralRe: Where is the graph? Pin
Dmitri Nesteruk28-Jun-09 10:53
memberDmitri Nesteruk28-Jun-09 10:53 
GeneralRe: Where is the graph? Pin
Marc Clifton28-Jun-09 11:01
protectorMarc Clifton28-Jun-09 11:01 
GeneralGood job, but can be slow for large solutions Pin
ZTransform22-Jun-09 7:06
memberZTransform22-Jun-09 7:06 
GeneralRe: Good job, but can be slow for large solutions Pin
Marc Clifton22-Jun-09 11:31
protectorMarc Clifton22-Jun-09 11:31 
GeneralComment and a problem ... Pin
sdahlbac21-Jun-09 23:53
membersdahlbac21-Jun-09 23:53 
GeneralRe: Comment and a problem ... Pin
Marc Clifton22-Jun-09 6:58
protectorMarc Clifton22-Jun-09 6:58 
GeneralVery timely indeed Mr Clifton Pin
Sacha Barber20-Jun-09 7:00
mvpSacha Barber20-Jun-09 7:00 
GeneralRe: Very timely indeed Mr Clifton Pin
Marc Clifton28-Jun-09 10:23
protectorMarc Clifton28-Jun-09 10:23 
GeneralMy Vote of 5 Pin
programmersmind20-Jun-09 0:33
groupprogrammersmind20-Jun-09 0:33 
GeneralMy vote of 5 Pin
Dr.Luiji19-Jun-09 12:37
memberDr.Luiji19-Jun-09 12:37 
GeneralRe: My vote of 5 Pin
Dr.Luiji21-Jun-09 22:29
memberDr.Luiji21-Jun-09 22:29 
GeneralVery nice Mr C. Pin
Pete O'Hanlon18-Jun-09 13:59
mvpPete O'Hanlon18-Jun-09 13:59 
GeneralRe: Very nice Mr C. Pin
Marc Clifton19-Jun-09 8:20
protectorMarc Clifton19-Jun-09 8:20 
GeneralRe: Very nice Mr C. Pin
Pete O'Hanlon19-Jun-09 9:41
mvpPete O'Hanlon19-Jun-09 9:41 
Question??? Pin
Paw Jershauge18-Jun-09 1:25
memberPaw Jershauge18-Jun-09 1:25 
AnswerRe: ??? Pin
Marc Clifton18-Jun-09 3:20
protectorMarc Clifton18-Jun-09 3:20 
GeneralRe: ??? Pin
Paw Jershauge18-Jun-09 7:52
memberPaw Jershauge18-Jun-09 7:52 
QuestionVisual Studio Automation? Pin
Indivara17-Jun-09 16:42
memberIndivara17-Jun-09 16:42 
AnswerRe: Visual Studio Automation? Pin
Marc Clifton18-Jun-09 3:16
protectorMarc Clifton18-Jun-09 3:16 
GeneralGreat Pin
Daniel Vaughan17-Jun-09 13:13
memberDaniel Vaughan17-Jun-09 13:13 
GeneralRe: Great Pin
Marc Clifton18-Jun-09 3:24
protectorMarc Clifton18-Jun-09 3:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.171114.1 | Last Updated 17 Jun 2009
Article Copyright 2009 by Marc Clifton
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid