Demonstrating MEF
I watched Glenn Block’s demonstration of the Managed Extensibility Framework on dnrTV last night, and came away wondering why the demo didn’t “work”. I’m a big fan of MEF, and I could see what Glenn was doing, but you could tell that Carl didn’t quite grok it.
So I started thinking about the things that didn’t work in the dnrTV episode and how I would demo MEF to an audience that had never heard of it.
1. Don’t use the Program class
Applications that use MEF need an instance of a class to act as the “host” for imported objects. That’s fine for WPF applications, because they have a little baked-in class called App that gets created when the application runs. That means you can just add the instance of your App class to the CompositionContainer and it’ll work.
For console applications, though, there is no class that’s instantiated when the application runs. The whole thing happens from a static method called “Main” in your “Program” class. That means that if you want to use MEF, you have to either create a whole new class and use an instance of that, or (easier to do in demos) create an instance of the Program class. The problem, of course, is that as soon as someone sees this code:
class Program { static void Main(string[] args) { var p = new Program(); p.DoStuff(); }
… they get confused. “New program?” asked Carl on dnrTV. I can understand why. Why new up a Program instance when we’re in a static method?
Glenn has explained to me that console applications are the best way to demonstrate MEF, because they prove that it’s a “client-agnostic” framework. If you use WPF to demonstrate it then there’s a risk that your audience will think it’s something that only works with WPF. So by all means use a console application, but rip out the MEF bits and put them into a different class (for example, “MyMefApplication”). Then change your Main method so that it looks more like this:
class Program { static void Main(string[] args) { var app = new MyMefApplication(); app.DoStuff(); } }
The same holds true for Windows Forms to a lesser degree. It, too, all starts with a static Main method in a Program class. You can, however, get away with just using the main form in a WinForms app as your MEF host.
2. Start with DirectoryPartCatalog
When people think of extensibility, they immediately think of plug-ins, in the form of assemblies that a user can drop into a folder to extend an application. Certainly that’s what Carl was thinking when the MEF demonstration began. However, the easiest way to demonstrate MEF is to use an AttributedAssemblyPartCatalog and point it either at the current assembly or an assembly you’ve added a reference to. For a newbie, this is quite confusing. Why use MEF at all if you have to add a reference to the “plug-in” assembly?
Of course, there are lots of reasons why you’d use an AttributedAssemblyPartCatalog and point it at either the current assembly or a known, referenced assembly. For example, you might want to provide some “default” extensions. Comicster’s doing that at the moment in my test code – it provides a couple of default file formats as well as letting the user develop their own. So I add my own “default file formats” assembly to an AggregatingComposablePartCatalog, and then add a DirectoryPartCatalog for user-created file formats.
Having said that; starting with extensions in the same assembly (or one that you’ve explicitly referenced) is just too darn confusing for newcomers. Always make your first demo one that looks for files in a folder.
3. Make extensions that have some visible side-effect
One of the most confusing thing about the dnrTV demonstration was the fact that Glenn’s extension class (a “Reverb” class that implemented IEffect) didn’t actually do anything. Following Carl’s suggestion, he gave it a single method that accepted a byte array and returned a byte array. Since the extension didn’t provide any useful visual feedback, the only way Glenn could demonstrate that it was being loaded was by printing the count of his “Effects” collection at runtime. If the count was 0, no extensions were available. If it was 1, the “Reverb” extension had been imported.
This made for a pretty dry demo. If you want to really show the user that your extension has been loaded, make it throw something up on the screen. It might add a MenuItem to your form’s main menu, or it might call MessageBox.Show() to display a message. That way you can invoke the method and prove conclusively that the extension has been imported.
4. Don’t do anything too tricky up front
This kind of ties in with the first step in this post. Because Glenn was working with a “Program” class as his “host” instance, he got tricky. He used MEF itself to provide him with an instance of the class. That’s inspired and very cool, it’s confusing for people who are new to the concept of imports and exports. Carl was confused enough by the need to create an instance of the Program class in the first place, but this just took it to the next level.
Some of the MEF sample applications do some very nifty stuff like importing the main window of the app, so that any imports that need to be satisfied on that window can be done so without having to add that instance to the CompositionContainer. Again, this is a really neat trick, but try to find a way around it when you’re first demonstrating the framework. You’re just gonna freak people out.
5. MEF Rocks
I just want to reiterate that MEF is a really cool technology and you shouldn’t be scared of it. I don’t want this post to sound like I’m ripping on Glenn’s demo: everything he showed made sense to me as someone who has already sipped from the MEF kool-aid cup, and he was constrained by the example that Carl had offered up. Hopefully others might get some ideas from this post for their inevitable MEF demo at the local user group.
Comments
# Glenn Block
2/12/2008 5:34 PM
Hi Matt
Nice post, and I appreciate the feedback. Actually a lot of what you pointed out were learnings I walked away with after doing the talk, accept for the visible side-effect...which I think is a great idea.
In my defense, there was no prep. It was a last minute decision, Carl came and said "Hey let's do a DNR TV" and I was like "Right on". We literally just sat down in the speaker lounge right before my MEF talk and cracked it out. Not to mention that I was doing a million things that week as I just can't say no :-)
Regardless, I agree with all your points, and have one more to add. Every little bit of prep ahead of time helps. However, sometimes it's out of your control.
# mabster
2/12/2008 5:40 PM
Thanks Glenn!
I'm continually blown away with the state of the Internet today, where a nobody from down under such as myself can have a one-on-one conversation with a Microsoft PM on a product as cool as this. What a world.
# Torben
20/04/2010 7:59 PM
Did MS change something in .Net 4.0, the example showing in the video is not working
It can’t find the IEffect interface ?
# mabster
20/04/2010 8:20 PM
IEffect was an interface Glenn created for the purposes of the demo, Torben. It's not part of the framework (well, at least not the one you're talkiong about)!