Search code examples
c#.netreflectiondecompilerilspy

ILSpy, how to resolve dependencies?


I want to disassemble an entire .NET assembly with ILSpy.

I used this code as base:
http://skysigal.xact-solutions.com/Blog/tabid/427/entryid/2488/Default.aspx

And it works fine, just when I have an assembly that references Npgsql.dll (or any other non-gac assembly), then I get an AssemblyResolutionException.

Failed to resolve assembly: 'Npgsql, Version=2.0.11.92, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7'

I know how I can get the referenced assemblies, but how can I add them to ast ?

    // SqlWebAdmin.Models.Decompiler.DecompileAssembly("xy.dll");
    public static string DecompileAssembly(string pathToAssembly)
    {
        //Assembly assembly = Assembly.LoadFrom(pathToAssembly);
        System.Reflection.Assembly assembly = System.Reflection.Assembly.ReflectionOnlyLoadFrom(pathToAssembly);
        //assembly.GetReferencedAssemblies();

        //assembly.GetReferencedAssemblies(assembly);
        Mono.Cecil.AssemblyDefinition assemblyDefinition =
            Mono.Cecil.AssemblyDefinition.ReadAssembly(pathToAssembly);



        ICSharpCode.Decompiler.Ast.AstBuilder astBuilder = new ICSharpCode.Decompiler.Ast.AstBuilder(new ICSharpCode.Decompiler.DecompilerContext(assemblyDefinition.MainModule));
        astBuilder.AddAssembly(assemblyDefinition);


        //new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit);
        using (System.IO.StringWriter output = new System.IO.StringWriter())
        {
            astBuilder.GenerateCode(new ICSharpCode.Decompiler.PlainTextOutput(output));
            string result = output.ToString();
            return result;
        }

        return "";
    } // End Function DecompileAssembly

Solution

  • You need to tell Cecil, the underlying metadata reader that ILSpy is using, where your assemblies are. You can write:

    var resolver = new DefaultAssemblyResolver();
    resolver.AddSearchDirectory("path/to/my/assemblies");
    
    var parameters = new ReaderParameters
    {
        AssemblyResolver = resolver,
    };
    
    var assembly = AssemblyDefinition.ReadAssembly(pathToAssembly, parameters);
    

    This is the most natural way to tell Cecil where to resolve referenced assemblies. This way you can remove the line where you load the assembly using System.Reflection, and only use the ILSpy stack.