tags:

views:

1094

answers:

5

Aloha

Given a plug-in architecture (C# / .NET 3.5) with the plug-ins stored in the GAC, how can I list/load all dll's that contain types that implement my specific interface? In other words, I'd like to investigate which plug-ins for my application are installed on a machine, by looking in the GAC.

-Edoode

+3  A: 

The Gac is really just a directory on your machine like any other. Here's the typical breakdown:

c:\windows\assembly\GAC

                   \GAC_32

                   \GAC_MSIL

And maybe some others..

Within each of those folders, you'll find subfolders where the actual dll's are stored. You'll first need to write a recursive method to get you all the dll's found under \assembly\, (you can find these online easily if you're not comfortable doing it yourself). Once you have that list of dll's you can proceed to use Assembly.LoadFile to load up the assembly and check all the types to see if they implement a given interface.

My only suggestion would be to load up these dll's in a seperate appdomain so that you're not allowing any potential harmful dll's to get loaded into your app.

Some links:

Searching Directories.

Loading Assemblies and checking for a given interface.

Creating new AppDomain.

BFree
I can't overstate the importance of using another AppDomain. In fact, it's likely a better option to recycle the AppDomain's pretty aggressively, as your memory consumption will rise with every assembly you load.
Adam Robinson
+3  A: 

First a little clarification: a DLL cannot implement an interface. The DLL contains types that could implement a specific interface. Here's a .NET wrapper around fusion.dll that allows you to enumerate all the assemblies in the GAC. Once you have loaded the assembly with Assembly.Load you can try to find all the types that implement the specific interface:

foreach (var type in assembly.GetTypes())
{
    var myInterfaceType = typeof(IMyInterface);
    if (type != myInterfaceType && myInterfaceType.IsAssignableFrom(type))
    {
        Console.WriteLine("{0} implements IMyInterface", type);
    }
}
Darin Dimitrov
Thanks, gacapi (fusion.dll) was what I needed :) The rest I had.
edosoft
+1  A: 

You should look at the Type Selector Tool in Enterprise Library. It's probably not what you want directly, but it does what you are describing and you might be able to borrow some implementation from it.

JP Alioto
+2  A: 

To add to BFree's answer, I suggest that you could load the assemblies for reflection only. This gives you enhanced security (the assemblies aren't able to execute at all) without appdomains, and flexibility (you can load assemblies that are for a different architecture).

Neil Williams
Cool, you learn something new every day.
BFree
A: 

First off, I'd recommend not doing this. To do this, you have to load all the assemblies from the GAC. I'd recommend you have your user (or an admin, or whatever) tell you what assemblies to try to load from (though for that, you might want a list of all the options, which might be why you're asking this...)

That said, this might work, but it's throwing errors for several assemblies it should work for, and I'm not sure why.... Also, I'm not sure how to detect where the GAC is -- c:\windows\assembly is the default, but I don't know where the real value is stored (registry?)

var targetType = typeof(IComparable);
var errors = new List<Exception>();
var c = Directory.GetFiles(@"c:\windows\assembly", "*.dll", SearchOption.AllDirectories).ToList()
    .ConvertAll(f => Path.GetFileNameWithoutExtension(f))
    .Where(f => !f.EndsWith(".ni"))
    .Distinct().ToList()
    .ConvertAll(f => { try { return Assembly.ReflectionOnlyLoad(f); } catch (Exception ex) { errors.Add(ex); return null; } })
    .Where(a => a != null)
    .SelectMany(a => { try { return a.GetTypes(); } catch (Exception ex) { errors.Add(ex); return new Type[] { }; } })
    .Where(t => targetType.IsAssignableFrom(t));

Good luck with that.

Jonathan
I didn't notice darin's answer while writing mine -- that gacapi project sounds like a much better option to get the list of assemblies than reading the files in c:\windows\assembly.
Jonathan