This post was migrated from Justin’s personal blog, 'Codethinked.com.' Views, opinions, and colorful expressions should be taken in context, and do not necessarily represent those of Simple Thread (and were written under the influence of dangerous levels of caffeination).

In the last part of this series on the Managed Extensibility Framework, I showed you how MEF can let you set classes as exports, then declare a property as an import, and MEF will “plug-in” these types to the property. What we ended up with was two different types which wrote out to the console in different colors. In order to do this, we used an “AttributedAssemblyPartCatalog” which is just a part catalog that takes an assembly reference in order to discover all types which have “ExportAttribute” applied to it:

private void Compose()
{        
    var catalog = new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());
    var container = new CompositionContainer(catalog);
    container.AddPart(this);
    container.Compose();
}

In this post we are going to check out a different type of part catalog that instead of taking an assembly reference it takes a folder:

var catalog = new DirectoryPartCatalog(@".\plugins", true);

This is great because this allows us to have a folder in our application where we can just drop assemblies into and this part catalog will grab all of them and add them each as “AttributedAssemblyPartCatalog”s which will, as we said earlier, import all types that have “ExportAttribute” applied to them.

In this example we are going still use the IConsoleWriter interface from the last post, and we are going to put console writers in multiple dlls:

image

Inside of our console app’s directory we are going to create a plugins folder. We will be able to place dlls in this folder and MEF will retrieve exports from these dlls automatically. First I am going to create a host class to run all of our code from:

[Export(typeof(ConsoleWriterHost))]
public class ConsoleWriterHost
{
    [Import]
    public IEnumerable<IConsoleWriter> ConsoleWriters { get; set; }

    public void Run()
    {
        foreach (IConsoleWriter consoleWriter in ConsoleWriters)
        {
            consoleWriter.Write("Hello from the console!");
        }
    }
}

Now that we have this host which imports our “IConsoleWriter”s and exports itself, we can fire up our application like this:

public static void Main(string[] args)
{
    var catalogs = new ComposablePartCatalog[]
                       {
                           new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()),
                           new DirectoryPartCatalog(@".\plugins", true)
                       };
    
    var catalog = new AggregatingComposablePartCatalog(catalogs);
    var container = new CompositionContainer(catalog);     
    container.Compose();

    var consoleWriterHost = container.GetExportedObject<ConsoleWriterHost>();
    consoleWriterHost.Run();                
}

In this code we are declaring two part catalogs in an array. One is an “AttributedAssemblyPartCatalog” which will allow us to gather up the Exports from the current dll (which is the ConsoleWriterHost) and then second is a “DirectoryPartCatalog” which points at the “plugins” folder and gets our exports.

We then pass these catalogs into an “AggregatingComposablePartCatalog” which is a catalog that simply takes in multiple other catalogs. We then pass it into the “CompositionCatalog” and call “Compose” just as we always do. After that we call the “GetExportedObject” method on the container to request the ConsoleWriterHost and then run it. Depending on what dlls we have in the plugins directory, we will get a different number of “IConsoleWriter”s. If we have these dlls in the folder:

image

Then we will get this output:

image 

Now that you have seen how to get exports from external dlls, I hope you can start to see a little bit of the cool features that MEF has to offer you. In the next entry we are going to look at export lifetimes and see how we can have our imports get updated whenever we drop new dlls in the folder.

6 Comments

Ivan Kotev

One thing that came up in my mind when I saw that DirectoryPartCatalog – what about security 🙂
Does MEF offer any automated ways to check the assemblies in the plugin folder or we must write some custom logic ?

Reply
Justin Etheredge

@Ivan MEF handles the enumerations of files in the folder (and gathers up the exports), but your process must have rights to access to that folder. I’m honestly not really sure what your question is.

Reply
Ivan

Ok, I didn’t make myself clear enough. What if somebody inject their own assemblies in the folder, then he/she will be able to intercept all calls.

Reply
Justin Etheredge

Yep, MEF simply loads the dlls from a particular folder. I think the idea is that any plugins which are dropped in that folder will be automatically loaded. I’ll have to look and see what hooks MEF provides for checking plugin assemblies before loading them.

Reply
Robert G

Justin,

Why does the collection of plugins need to be in the ConsoleWriterHost class? Is this required by MEF? Why can’t the collection be in your main class.

It’s unnecessarily complicating the Compose method, which already smells bad.

Reply
Justin Etheredge

@Robert Nope, it doesn’t. You could have it on the "Program" class, but then you need to instantiate the class and add it to the catalog so that MEF can "inject" dependencies into it.

Reply

Leave a Reply

Your email address will not be published. Required fields are marked *