Neil Barnwell
Neil Barnwell

Reputation: 42095

View NuGet package dependency hierarchy

Is there a way, either textual or graphical, to view the hierarchy of dependencies between NuGet packages?

Upvotes: 143

Views: 85350

Answers (13)

KevinBui
KevinBui

Reputation: 1099

I built a powershell script net-pkg.psm1 to draw hierarchy of dependencies.

The script works by reading file .\obj\project.assets.json (the file when you run dotnet restore)

Assume you are in Windows OS with Powershell built-in. Just download the file net-pkg.psm1 and run these command to see it work.

> ipmo -Force "C:\dev-note\learning\dotnet\net-pkg.psm1"
> cd E:\path\to\folder\of\csproj
> initialize-asset
> build-map 'net8.0'
> show-tree

└─ net8.0
   ├─ Microsoft.AspNetCore.Mvc.NewtonsoftJson/8.0.3
   ├─ MyOrg.Proj.Jobs/2.3.0
   │  ├─ MyOrg.Proj.Persistence.CosmosDb/10.0.1
   │  │  ├─ Microsoft.Extensions.DependencyInjection.Abstractions/8.0.0
   │  │  ├─ MyOrg.Proj.Persistence.Abstractions/10.0.1
   │  │  │  ├─ Newtonsoft.Json/13.0.2 - 13.0.3
   │  │  │  └─ MyOrg.Proj.Requests.Abstractions/6.0.0
   │  │  ├─ Azure.ResourceManager.CosmosDB/1.2.1
   │  │  ├─ MyOrg.Proj.ManagedIdentity.Cosmos/4.0.2
   │  │  │  ├─ MyOrg.Proj.ManagedIdentity/4.0.2
   │  │  │  │  └─ Microsoft.Extensions.Configuration.Abstractions/8.0.0
   │  │  │  └─ Microsoft.Azure.Cosmos/3.35.4
   │  │  └─ Microsoft.AspNetCore.Hosting.Abstractions/2.2.0
   │  └─ MyOrg.Proj.Persistence.InMemory/10.0.1
   │     ├─ MyOrg.Proj.Persistence.Abstractions/10.0.1
   │     └─ MyOrg.Proj.Requests.Abstractions/6.0.0
   └─ Microsoft.Extensions.DependencyInjection.Abstractions/8.0.0

Upvotes: 1

Eugene Petrenko
Eugene Petrenko

Reputation: 4982

Package Visualizer from NuGet 1.4 should work. See http://docs.nuget.org/docs/release-notes/nuget-1.4

Upvotes: 7

Ohad Schneider
Ohad Schneider

Reputation: 38106

Having gone through all existing answers, IMHO they are incomplete and/or obsolete. Fortunately, it seems that today there are several good options:

Or roll your own using the modern APIs (not Nuget.Core):

private static async Task GetRecursiveDependenciesCore(string id, string version, ConcurrentQueue<string> dependencies)
{
    var sourceRepository = new SourceRepository(new PackageSource(NugetOrgSource), Repository.Provider.GetCoreV3());
    var dependencyResource = await sourceRepository.GetResourceAsync<DependencyInfoResource>(CancellationToken.None);
    var package = await dependencyResource.ResolvePackage(new PackageIdentity(id, new NuGetVersion(version)), NuGetFramework.AnyFramework, new NugetLogger(), CancellationToken.None);
    if (package == null)
    {
        throw new InvalidOperationException("Could not locate dependency!");
    }

    foreach (var dependency in package.Dependencies)
    {
        dependencies.Enqueue(dependency.Id + " " + dependency.VersionRange.MinVersion);
    }

    await Task.WhenAll(package.Dependencies.Select(d => GetRecursiveDependenciesCore(d.Id, d.VersionRange.MinVersion.ToNormalizedString(), dependencies)));
}

Upvotes: 5

MartyIX
MartyIX

Reputation: 28648

.NET has a built-in feature now:

dotnet list package --include-transitive

which can print an output as follows:

Project 'Maui.Controls.Sample.Sandbox' has the following package references
   [net8.0-windows10.0.19041]:
   Top-level Package                               Requested   Resolved
   > Microsoft.Extensions.DependencyInjection      8.0.0       8.0.0

   Transitive Package                                           Resolved
   > libsodium                                                  1.0.19
   > LZMA-SDK                                                   22.1.1
   > Microsoft.AspNetCore.Authorization                         8.0.0
   > Microsoft.AspNetCore.Components                            8.0.0
   > Microsoft.AspNetCore.Components.Analyzers                  8.0.0
   > Microsoft.AspNetCore.Components.Forms                      8.0.0
   [..]

so unfortunately, it's not really hierarchical but it gives the dependencies.

For a better dependency hierarchy which does rely on external tools, one can enable generating of JSON lock files (packages.lock.json files) in her C# project using

<PropertyGroup>
    <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>

then run dotnet restore and check contents of your packages.lock.json file:

{
  "version": 1,
  "dependencies": {
    "net8.0-windows10.0.19041": {
      "Microsoft.Extensions.DependencyInjection": {
        "type": "Direct",
        "requested": "[8.0.0, )",
        "resolved": "8.0.0",
        "contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==",
        "dependencies": {
          "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
        }
      },
      "libsodium": {
        "type": "Transitive",
        "resolved": "1.0.19",
        "contentHash": "tupm/HViwBN6Knd/gckR+cLaJGR39GLmiU4iDMM5hp/1BoczMr8fwJhSU+3/C2V4hi9nBK/4FICRKtTLU30TCA=="
      },
      "LZMA-SDK": {
        "type": "Transitive",
        "resolved": "22.1.1",
        "contentHash": "lxG8/H53OCqebnDFlTStwzbgtmUN/DqnXN8kffa/ctHcSEHhIPDyEa3jLzpZxVX5F8bmJgvb1mna6gnhetykIw=="
      },
      "Microsoft.AspNetCore.Authorization": {
        "type": "Transitive",
        "resolved": "8.0.0",
        "contentHash": "OGIGJMnlWvQgcweHcv1Mq/P24Zx/brUHeEdD05NzqkSXmQSnFomTvVyCuBtCXT4JPfv2m70y1RSocmd9bIbJRg==",
        "dependencies": {
          "Microsoft.AspNetCore.Metadata": "8.0.0",
          "Microsoft.Extensions.Logging.Abstractions": "8.0.0",
          "Microsoft.Extensions.Options": "8.0.0"
        }
      },
      [..]

https://github.com/NuGet/Home/issues/6188 is unfortunately still open.

Upvotes: 0

Hamed Moghadasi
Hamed Moghadasi

Reputation: 1673

If you need more than 1 depth of dependencies and more detailed information about your packages, you can also check the below file in your project:

{project directory}\bin\Debug\net8.0\<project name>.deps.json

enter image description here

Upvotes: 4

Javier Solis
Javier Solis

Reputation: 131

I add a compatible solution with the latest version of nuget-core

install-package nuget.core

This is the console App to get the dependencies graph

    class Program
    {
        static void Main()
        {
            Console.Write("Enter the local repo folder: ");
            var repoFolder = Console.ReadLine();
            
            var repo = new LocalPackageRepository(repoFolder);
            IQueryable<IPackage> packages = repo.GetPackages();
            OutputGraph(repo, packages, 0);
        }

        static void OutputGraph(LocalPackageRepository repository, IEnumerable<IPackage> packages, int depth)
        {
            foreach (IPackage package in packages)
            {
                Console.WriteLine("{0}{1} v{2}", new string(' ', depth), package.Id, package.Version);

                IList<IPackage> dependentPackages = new List<IPackage>();
                foreach (var dependencySet in package.DependencySets)
                {
                    foreach (var dependency in dependencySet.Dependencies)
                    {
                        var dependentPackage = repository.FindPackage(dependency.Id, dependency.VersionSpec, true, true);
                        if (dependentPackage != null)
                        {
                            dependentPackages.Add(dependentPackage);
                        }
                    }       
                }

                OutputGraph(repository, dependentPackages, depth + 3);
            }
        }
    }

Upvotes: 12

John Jang
John Jang

Reputation: 2965

If you're using the new .csproj, you could get all dependencies with reference in here (after project built):

{ProjectDir}\obj\project.assets.json

enter image description here

Upvotes: 111

Josef Ginerman
Josef Ginerman

Reputation: 1560

Since this is an old question, it is important to note the following:

This is a built-in feature in the new csproj format. In Visual Studio 2017 and up, open the Solution Explorer and you can find you packages like:

{Your project}->Dependencies->Packages

You can open each NuGet dependency tree and run with it recursively, effectively seeing not only the dependency tree for specific packages, but also which NuGet packages your project actually installs.

Upvotes: 8

Eyal Ben Moshe
Eyal Ben Moshe

Reputation: 2425

Another option you have is to use the nuget-deps-tree npm package. It supports both the packages.config format and the newer assets format used by .NET projects.

Upvotes: 5

Neil Barnwell
Neil Barnwell

Reputation: 42095

It is also possible to write code against the API in NuGet.Core. Install it via NuGet:

install-package nuget.core

Then you can get a repository object and walk the graph. Here's a sample app I just built:

using System;
using System.Collections.Generic;
using System.Linq;
using NuGet;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main()
        {    
            var repo = new LocalPackageRepository(@"C:\Code\Common\Group\Business-Logic\packages");
            IQueryable<IPackage> packages = repo.GetPackages();
            OutputGraph(repo, packages, 0);
        }

        static void OutputGraph(LocalPackageRepository repository, IEnumerable<IPackage> packages, int depth)
        {
            foreach (IPackage package in packages)
            {
                Console.WriteLine("{0}{1} v{2}", new string(' ', depth), package.Id, package.Version);

                IList<IPackage> dependentPackages = new List<IPackage>();
                foreach (var dependency in package.Dependencies)
                {
                    dependentPackages.Add(repository.FindPackage(dependency.Id, dependency.VersionSpec.ToString()));
                }

                OutputGraph(repository, dependentPackages, depth += 3);
            }
        }
    }
}

In my case, this app outputs something like this:

MyCompany.Castle v1.1.0.3
   Castle.Windsor v2.5.3
      Castle.Core v2.5.2
      MyCompany.Common v1.1.0.6
         CommonServiceLocator v1.0
            MyCompany.Enum v1.1.0.7
   MyCompany.Common v1.1.0.6
      CommonServiceLocator v1.0
         MyCompany.Enum v1.1.0.7
      MyCompany.Enum v1.1.0.7
         MyCompany.Versioning v1.3
            Castle.Core v2.5.2
               Castle.Windsor v2.5.3
                  Castle.Core v2.5.2
                  CommonServiceLocator v1.0
                     NUnit v2.5.10.11092
                        RhinoMocks v3.6

Upvotes: 28

Gian Marco
Gian Marco

Reputation: 23169

Like @neil-barnwell solution, but works with NuGet.Core 2.7+

Install-Package NuGet.Core

Here is the code

using System;
using System.Linq;
using System.Runtime.Versioning;
using System.IO;
using NuGet;

public class Program
{
    public static void Main(string[] args)
    {
        var frameworkName = new FrameworkName(".NETFramework, Version=4.0");

        // var packageSource = "https://www.nuget.org/api/v2/";
        var packageSource = Path.Combine(Environment.GetEnvironmentVariable("LocalAppData"), "NuGet", "Cache");

        var repository = PackageRepositoryFactory.Default.CreateRepository(packageSource);
        const bool prerelease = false;

        var packages = repository.GetPackages()
            .Where(p => prerelease ? p.IsAbsoluteLatestVersion : p.IsLatestVersion)
            .Where(p => VersionUtility.IsCompatible(frameworkName, p.GetSupportedFrameworks()));

        foreach (IPackage package in packages)
        {
            GetValue(repository, frameworkName, package, prerelease, 0);
        }

        Console.WriteLine();
        Console.WriteLine("Press Enter...");
        Console.ReadLine();
    }

    private static void GetValue(IPackageRepository repository, FrameworkName frameworkName, IPackage package, bool prerelease, int level)
    {

        Console.WriteLine("{0}{1}", new string(' ', level * 3), package);
        foreach (PackageDependency dependency in package.GetCompatiblePackageDependencies(frameworkName))
        {
            IPackage subPackage = repository.ResolveDependency(dependency, prerelease, true);
            GetValue(repository, frameworkName, subPackage, prerelease, level + 1);
        }
    }
}

Upvotes: 34

0xced
0xced

Reputation: 26468

I Can Has .NET Core (GitHub repository) produces nice graphs of NuGet dependencies along with a Graphviz representation. And as its name implies, you also get .NET Core compatibility information for free.

If you prefer to run it locally on your computer, I Can Has .NET Core also offers a console mode.

NuGet dependencies graph sample (web)

NuGet dependencies graph sample (Graphviz)

Upvotes: 13

N. Kudryavtsev
N. Kudryavtsev

Reputation: 4071

I've found a nice NPM package to print the dependency tree into console. Of course if you don't mind using/installing NPM/Node.JS.

Considering other solutions, this is the most simple one, you don't need to write your own code or register something, and you get just such dependency tree as you expect. But it works only with packages.config format.

I can't believe this functionality is absent in free Visual Studio editions or nuget.exe too.

Upvotes: 28

Related Questions