Dependency graph of Visual Studio projects

Viewed 111556

I'm currently migrating a big solution (~70 projects) from VS 2005 + .NET 2.0 to VS 2008 + .NET 3.5. Currently I have VS 2008 + .NET 2.0.

The problem is that I need to move projects one by one to new .NET framework ensuring that no .NET 2.0 project references .NET 3.5 project. Is there any tool that would give me a nice graph of project dependencies?

17 Answers

Have you tried NDepend? It'll shows you the dependencies and you can also analyze the usability of your classes and methods.

Their website:

http://ndepend.com

Made the powershell scripts .etc. posted here into a dotnet tool.

Try DependenSee

to install

  • Make sure you have dotnet 5 runtime installed

  • Make sure you have dotnet 6 runtime installed

  • run dotnet tool install dependensee --global

  • once installed, run dependensee "path/to/root/of/csproj/files" "path/to/output.html"

  • By default it doesn't include nuget packages, but can be enabled with -P switch

  • to see all options, run dependensee with no args.

HTML output looks like this

DependenSee Graph

For Continuous Integration Scenarios

There are command line options allowing you to output XML or JSON for further processing, either writing them to a file or writing to Standard Output allowing to pipe the output to other command line tools without touching the filesystem if necessary.

You can create a dependency graph of your projects in VS 2010 Ultimate. Architecture Explorer lets you browse your solution, select projects and the relationships that you want to visualize, and then create a dependency graph from your selection.

For more info, see the following topics:

How to: Generate Graph Documents from Code: http://msdn.microsoft.com/en-us/library/dd409453%28VS.100%29.aspx#SeeSpecificSource

How to: Find Code Using Architecture Explorer: http://msdn.microsoft.com/en-us/library/dd409431%28VS.100%29.aspx

RC download: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=457bab91-5eb2-4b36-b0f4-d6f34683c62a.

Visual Studio 2010 Architectural Discovery & Modeling Tools forum: http://social.msdn.microsoft.com/Forums/en-US/vsarch/threads

This extended version of the PS Script from Danny Tuppeny shows both Project and External references:

Function Get-ProjectReferences($rootPath)
{
  $projectFiles = Get-ChildItem $rootPath -Filter *.csproj -Recurse
  $ns = @{ defaultNamespace = "http://schemas.microsoft.com/developer/msbuild/2003" }

  $projectFiles | ForEach-Object {
    $projectFile = $_ | Select-Object -ExpandProperty FullName
    $projectName = $_ | Select-Object -ExpandProperty BaseName
    $projectXml = [xml](Get-Content $projectFile)

    $projectReferences = $projectXml | Select-Xml '//defaultNamespace:ProjectReference/defaultNamespace:Name' -Namespace $ns | Select-Object -ExpandProperty Node | Select-Object -ExpandProperty "#text"
    $projectReferences | ForEach-Object {
        "PR:[" + $projectName + "]:[" + $_ + "]"
    }
  }

  $projectFiles | ForEach-Object {
    $projectFile = $_ | Select-Object -ExpandProperty FullName
    $projectName = $_ | Select-Object -ExpandProperty BaseName
    $projectXml = [xml](Get-Content $projectFile)

    $externalReferences = $projectXml | Select-Xml '//defaultNamespace:Reference/@Include' -Namespace $ns
    $externalReferences | ForEach-Object {
        "ER:[" + $projectName + "]:[" + $_ + "]"
    }

  }

}

Get-ProjectReferences "C:\projects" | Out-File "C:\temp\References.txt"

It will give a colon-separated file that can be opened and analysed in Excel.

This extended version of the PS Script from Danny Tuppeny shows references for both csproj and vcxproj files, and also supports

-Depth - maximum dependency chain length

-Like - prints only dependency chains starting with projects with name -like $Like

-UntilLike - cuts dependency chains on projects with name -like $UntilLike

-Reverse - prints reversed dependency chains ([proj] <- [referencing proj])

[CmdletBinding()]
param (
    [Parameter(Mandatory=$false)]
    [string]$RootFolder = ".",
    [Parameter(Mandatory=$false)]
    [string]$Like = "*",
    [Parameter(Mandatory=$false)]
    [string]$UntilLike = "*",
    [Parameter(Mandatory=$false)]
    [switch]$Reverse,
    [Parameter(Mandatory=$false)]
    [int]$Depth=1
)

$arrow = if ($script:Reverse) { "<-" } else { "->" }

Function PrintTree ($projectNameToProjectNameList, $projectName, $maxDepth = 1, $prefix = "")
{
    $print = $script:UntilLike -eq "*" -or $projectName -Like $script:UntilLike
    $stop = $projectNameToProjectNameList[$projectName].count -eq 0 -or $maxDepth -eq 0 -or ($script:UntilLike -ne "*" -and $projectName -Like $script:UntilLike)
    
    if ($stop) {
        if ($print) {
            $prefix + "[$projectName]"
        }
    } else {
        $prefix += "[$projectName] $arrow "
        --$maxDepth
        $projectNameToProjectNameList[$projectName] | % { PrintTree $projectNameToProjectNameList $_ $maxDepth $prefix }
    }
}

Function Get-ProjectReferences ($rootFolder)
{
    $projectFiles = Get-ChildItem $rootFolder -Filter *.csproj -Recurse
    $projectFiles += Get-ChildItem $rootFolder -Filter *.vcxproj -Recurse
    $ns = @{ defaultNamespace = "http://schemas.microsoft.com/developer/msbuild/2003" }
    
    $projectGuidToProjectName = @{}
    $projectNameToProjectReferenceGuidList = @{}

    $projectFiles | ForEach-Object {
        $projectFile = $_ | Select-Object -ExpandProperty FullName
        $projectName = $_ | Select-Object -ExpandProperty BaseName
        $projectXml = [xml](Get-Content $projectFile)
        
        $projectGuid = $projectXml | Select-Xml '//defaultNamespace:ProjectGuid' -Namespace $ns | Select-Object -ExpandProperty Node | Select-Object -ExpandProperty "#text" | % { $_ -as [Guid] }
        $projectGuidToProjectName[$projectGuid] = $projectName

        $projectReferenceGuids = $projectXml | Select-Xml '//defaultNamespace:ProjectReference/defaultNamespace:Project' -Namespace $ns | Select-Object -ExpandProperty Node | Select-Object -ExpandProperty "#text" | % { $_ -as [Guid] }
        if ($null -eq $projectReferenceGuids) { $projectReferenceGuids = @() }
        $projectNameToProjectReferenceGuidList[$projectName] = $projectReferenceGuids
    }

    $projectNameToProjectReferenceNameList = @{}
    foreach ($projectName in $projectNameToProjectReferenceGuidList.keys) {
        $projectNameToProjectReferenceNameList[$projectName] = $projectNameToProjectReferenceGuidList[$projectName] | % { $projectGuidToProjectName[$_] } | sort
    }
    
    if ($script:Reverse) {
        $projectReferenceNameToProjectNameList = @{}
        foreach ($projectName in $projectNameToProjectReferenceNameList.keys) {
            foreach ($projectReferenceName in $projectNameToProjectReferenceNameList[$projectName]) {
                if (!$projectReferenceNameToProjectNameList.ContainsKey($projectReferenceName)) { $projectReferenceNameToProjectNameList[$projectReferenceName] = @() } 
                $projectReferenceNameToProjectNameList[$projectReferenceName] += $projectName
            }
        }

        foreach ($projectName in $projectReferenceNameToProjectNameList.keys -Like $script:Like) {
            PrintTree $projectReferenceNameToProjectNameList $projectName $script:Depth
        }
    } else {
        foreach ($projectName in $projectNameToProjectReferenceNameList.keys -Like $script:Like) {
            PrintTree $projectNameToProjectReferenceNameList $projectName $script:Depth
        }
    }
}

Get-ProjectReferences $RootFolder

If you're looking for a way that doesn't require any external tools, you can navigate to a project's obj/project.assets.json file. This file is generated during build, and has a hierarchical JSON structure of the dependencies (both project references and nuget packages).

It's useful for answering questions like "why the hell is this project DLL being pulled into the build directory?"

Related