Visualize project dependencies in Visual Studio

When approaching a new body of code, I like to have a map. This helps me see where to start looking, what avenues to ignore for now, and why the previous authors made the decisions they did.

Accurate documentation is never available. It's just too costly to maintain. I think we've finally stopped beating the "not enough documentation" drum. Now we turn to the code itself.

For a quick first glance at a Visual Studio solution, I run this handy macro.

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports System.Diagnostics
Imports VSLangProj
Imports System.IO

Public Module Diagram

    Sub ProjectDependency()
        Dim vsProject As VSProject
        Dim file As Integer
        Dim writer As New StreamWriter(DTE.Solution.FileName & ".dot")

        writer.WriteLine("digraph """ & DTE.Solution.FullName & """ {")
        writer.WriteLine("  rankdir=LR")

        For Each project As Project In DTE.Solution.Projects
            vsProject = TryCast(project.Object, VSProject)
            If Not vsProject Is Nothing Then
                For Each reference As Reference In vsProject.References
                    If Not reference.SourceProject Is Nothing Then
                        writer.WriteLine("  """ & project.Name & """->""" & reference.SourceProject.Name & """")
                    End If
                Next
            End If
        Next

        writer.WriteLine("}")
        writer.Dispose()
    End Sub

End Module

This generates a ".dot" file in the solution's folder. Run this through GraphViz to generate a graphical dependency map of the projects in the solution.

Then I start at the left side of the graph, which is where the entry points end up. I work my way down through the layers in a more-or-less breadth-first search of the project space. Tightly coupled project groups end up looking messy, and loosely coupled project groups end up looking neat.

Once I've oriented myself with this coarse map, I'll get more fine grained with a tool like NDepend. But this is a great first step.

12 Responses to “Visualize project dependencies in Visual Studio”

  1. Edo van Vliet Says:

    Thanks man, this worked like a charm for me :)

    -Edoode

  2. Attila Says:

    It didn't work for me in VS 2008. :(

  3. Michael L Perry Says:

    Strange. I developed this macro in VS 2008. Can you tell me what it's doing?

  4. Chris Says:

    I'm having a few problems as well. I *think* it's working on the VS side, but I'm not sure what the results should look like. I'm not familiar with GraphViz at all, and that actually may be where the problem is. I did the following on VS08:
    Step 1: New Macro Project (named: ProjectReferenceMap)
    Step 2: Renamed Module1 to CreateFile
    Step 3: Double click it, opens new instance
    Step 4: Copy/Paste your code into it, save
    Step 5: Click F5/Green Arrow
    Step 6: Generates a SolutionFileName.sln.dot file in the same directory as the solution file itself.
    I opened up the .dot file it generated as this is what it put out.
    digraph "C:\svn_repos\branches\path\to\solution\SolutionName.sln" {
    rankdir=LR
    }

    I tried opening GraphViz -> GVedit.exe and opened the generated .dot file into it, clicked the Run button, and all it created was a small white box of an image.

    I'm not sure where I went wrong, any help would be greatly appreciated.

  5. Michael L Perry Says:

    Chris,

    It looks like you didn't have any projects that reference other projects in your solution. References to outside assemblies are not captured.

    The generated file should have some arrows in it, like this:

    digraph "C:\svn_repos\branches\path\to\solution\SolutionName.sln" {
    rankdir=LR
    ProjectA->ProjectB
    ProjectA->ProjectC
    ProjectB->ProjectC
    }

    ProjectA, ProjectB, and ProjectC are all in the same sln.

  6. Stuart Says:

    If you have solution folders then this code will not work. I hacked it to work using code below:
    Imports System
    Imports EnvDTE
    Imports EnvDTE80
    Imports EnvDTE90
    Imports System.Diagnostics
    Imports VSLangProj
    Imports System.IO

    Public Module Module2

    Public Sub ProjectDependency()

    Dim file As Integer
    Dim writer As New StreamWriter(DTE.Solution.FileName & ".dot")

    writer.WriteLine("digraph """ & DTE.Solution.FullName & """ {")
    writer.WriteLine(" rankdir=LR")

    For Each project As Project In DTE.Solution.Projects
    NavProj(project, writer)
    Next

    writer.WriteLine("}")
    writer.Dispose()
    End Sub

    Sub NavProj(ByVal proj As Project, ByVal writer As StreamWriter)
    Dim outputPathProperty As EnvDTE.Property
    Dim outputPath As String
    Dim vsProject As VSProject

    If Not (proj.ConfigurationManager Is Nothing) Then
    ' It's a project!
    outputPathProperty = proj.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath")
    If Not (outputPathProperty Is Nothing) Then
    vsProject = TryCast(proj.Object, VSProject)
    If Not vsProject Is Nothing Then
    For Each reference As Reference In vsProject.References
    If Not reference.SourceProject Is Nothing Then
    writer.WriteLine(" """ & proj.Name & """->""" & reference.SourceProject.Name & """")
    End If
    Next
    End If
    End If
    Else
    NavProjItems(proj.ProjectItems, writer)
    End If
    End Sub
    Sub NavProjItems(ByVal projItems As ProjectItems, ByVal writer As StreamWriter)
    Dim projectItem As EnvDTE.ProjectItem

    If Not (projItems Is Nothing) Then
    For Each projectItem In projItems
    If Not (projectItem.SubProject Is Nothing) Then
    ' Recurse, can be an Enterprise project in
    ' Visual Studio .NET 2002/2003 or a solution folder in VS 2005
    NavProj(projectItem.SubProject, writer)
    End If
    Next
    End If
    End Sub

    End Module

  7. Bojan Says:

    Works in Visual Studio 2010 as well. Thanks a lot!

    Any ideas how to make it look a bit nicer? :)

    Anyway, good stuff... Cheers.

  8. Bojan Says:

    Found the way - edited the produced files, they have solid documentation on GraphViz project site.
    Good stuff, produced an awesome graph from the solution with 20 something projects. :D
    Thanks once again.
    :)

  9. Michael L Perry Says:

    Bojan,

    Please share the changes you made to the dot files. How did you make it look better?

  10. Bon Says:

    Thank you for for this article

  11. tim Says:

    Hello Michael,

    Does your macro also work for C++-solutions. I tried yours and Stuart's solution, but no .dot file was generated when running the macro neither in visual studio's macro editor nor when selecting the solution in the solution explorer and running a shortcut for the macro. Any ideas?

    Cheers,
    Tim

  12. Michael L Perry Says:

    Hi, Tim. I haven't tried this macro on C++ projects, so I can't promise that it works. But I don't think there is anything language specific in the macro. Can you debug and step through it to see where it goes wrong?

Leave a Reply

You must be logged in to post a comment.