How to get a list of all packages that a .NET solution ACTUALLY requires?

88 Views Asked by At

Suppose I have a large .NET solution consisting of multiple projects. Each of these projects has some NuGet dependencies. These direct dependencies will also have some transitive dependencies but it's possible that the project in question doesn't actually need that transitive dependency.

Eg:

Package A:

public class A() {
    
}

public void DoSomething() {
    Console.WriteLine();
}

public B CreateB() {
    return new B();
}

Package B:

public B() {
     ;
}

If I have just 1 project in my solution that only uses A.DoSomething() and never calls A.CreateB() and also does not directly reference Package B, then even though B is a transitive dependency for my solution, it's not actually needed.

Is there some existing tool that helps me get a list of all packages that are actually needed by my solution?

I have a product which I ship through an installer. I often miss including transitive dependencies in the installer and as a result, the application fails at runtime.

1

There are 1 best solutions below

1
Vladyslav Lishchyna On

This is interesting task and I think here is no simply answer (or maybe I don`t know it)

As for me solution will looks like external code analyze tool, previously i wrote something like this use Nuget package https://www.nuget.org/packages/Mono.Cecil/

This package it`s different reflection and you can use it for find information about every single line of code in your project.

So you need to:

  • get all classes
  • get all methods in all classes
  • get all lines of code in all methods
  • filter line, get only lines that have other methods call
  • get all namespaces that this methods have
  • group by namespaces

after that you can match really used namespaces and nuget packages and which of them really used

Here is code example how you can do this:

  var usedNamespaces = AssemblyDefinition //class from Mono.Ceccill nuget package
    .ReadAssembly("path to your dll") // assembly reading
    .Modules
    .SelectMany(m => m.Types) //get all types
    .SelectMany(t => t.Methods) //get all methods
    .Where(m => m.Body != null) //ignore abstract methods
    .SelectMany(m => m.Body.Instructions) //get each line of methods code
    .Distinct() //ignore the same
    .Where(i => i.Operand != null)
    .Where(i => i.Operand is MethodReference) //get only that lines that call some other methods
    .Select(i => (MethodReference) i.Operand)
    .Select(r => r.DeclaringType.Namespace) //get used methods namespaces
    .Distinct() //ignore the same
    .ToList();

This is just example you can upgrade it for your needs, but its works enter image description here