简体   繁体   中英

How to get a list of all referenced assemblies (loaded or not)

I am trying to get a list of referenced assemblies for a an assembly I load into a main app in MEF.

I want to make sure that all the referenced assemblies are present in the folder before running the plugin.

I tried using

List<AssemblyName> a = Assembly.GetEntryAssembly().GetReferencedAssemblies().ToList();

But when I do this, it only shows me assemblies used/loaded at that stage. I want a complete list (at runtime) of assemblies referenced (a replica of the References Folder in VS) regardless of whether they are used at that moment or at all.

Before loading the plugin, you can load it for reflection only that will load only the metadata of the file. For example:

    var assm = Assembly.ReflectionOnlyLoadFrom(@"Same.dll");
    var reff = assm.GetReferencedAssemblies();

Keep in mind that the associated library can have their references.

You can extract that information from the file metadata. Quickest way is probably to use one of the libraries out there to do so.

For example you can use Mono.Cecil

Like this:

var md = ModuleDefinition.ReadModule(assemblyPath);
foreach (var reference in md.AssemblyReferences)
{

}

I was struggling with this too and came up with Assembly.GetReferencedAssemblies() . This will give you all the referenced assemblies in an assembly. However, to get them all in the whole application you need to do a transitive closure to get the assemblies referenced by the references and so on.

Here is a function that worked for me.

    private static List<Assembly> GetAllReferencedAssemblies(Assembly asm)
    {
        var nameQueue = new Queue<AssemblyName>(asm.GetReferencedAssemblies());
        var alreadyProcessed = new HashSet<string>() { asm.FullName };
        var result = new List<Assembly>();
        result.Add(asm);
        while (nameQueue.Any())
        {
            var name = nameQueue.Dequeue();
            var fullName = name.FullName;
            if (alreadyProcessed.Contains(fullName) || fullName.StartsWith("Microsoft.") || fullName.StartsWith("System."))
                continue;
            alreadyProcessed.Add(fullName);
            try
            {
                var newAssembly = Assembly.Load(name);
                result.Add(newAssembly);
                foreach (var innerAsmName in newAssembly.GetReferencedAssemblies())
                    nameQueue.Enqueue(innerAsmName);
                Debug.WriteLine(name);
            }
            catch (Exception e)
            {
                Debug.WriteLine(e);
            }
        }

        return result;
    }

A couple of practical points: you will see that I added a line to exclude Microsoft and System assemblies -- if you go down that rabbit whole you get a crazy number of assemblies. However, you can adjust as you see fit. Also, I wrapped the Assembly.Load in an try/catch block since my experience is sometimes you get some dlls you can't load, or that aren't used any more. Again, feel free to do as you will with this.

Obviously to you it you pass in the top level assembly you are using, the main program or whatever. You can call it easily with something like:

var asmList = GetAllReferencedAssemblies(typeof(Main).Assembly);

Where main is a type in your top level assembly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM