Simple Introduction to Extensible Applications with the Managed Extensions Framework


Recently my team has been working on the Managed Extensions Framework (MEF)… I have gotten a chance to explain the concept to folks and I think I have discovered a way to talk about MEF that folks can easily get.  So I thought I’d spend a little time walking through a *very* simple MEF example as a way to introduce folks to the power of extensible applications in general, and MEF in particular. 


BTW, you can download the current MEF CTP  and the final working sample.


Background


Let’s start with the most simple example: Hello World! 



   1: using System;
   2:  
   3: class Program
   4: {
   5:     public void Run()
   6:     {
   7:         Console.WriteLine(“Hello World!”);
   8:         Console.ReadKey();
   9:     }
  10:     static void Main(string[] args)
  11:     {
  12:         Program p = new Program();
  13:         p.Run();
  14:     }
  15: }

Now, you might now always want to print the same string, so let’s refactor slightly to pull the string out.. 



   1: public string Message { get; set; }
   2:  
   3: public void Run()
   4: {
   5:     Console.WriteLine(Message);
   6:     Console.ReadKey();
   7: }

This looks nice, now we need to add the message… well, the actual text is a separate concern, as such it should be in a different class.    Such as:



   1: public class SimpleHello 
   2: {
   3:     public string Message
   4:     {
   5:         get
   6:         {
   7:             return “hello world!!”;
   8:         }
   9:     }
  10: }

Now we simply need wire these up:



   1: public void Run()
   2: {
   3:     SimpleHello hello = new SimpleHello();
   4:     Message = hello.Message;
   5:  
   6:     Console.WriteLine(Message);
   7:     Console.ReadKey();
   8: }

This works, but something looks odd about line 3 and 4… We have introduced tight coupling back.. What we really want to do is externalize lines 3 and 4, so they can be controlled without effecting the rest of the logic of the program. 


 


Enter MEF


Add a Reference to the System.ComponentModel.Composition.dll assembly found in the bin directory of the MEF zip. 


Add



   1: using System.ComponentModel.Composition;

Now in the Program class, we need to import a value for Message — that is, we want to specify that someone outside of this program needs to supply a message.  Then we need to remove our tight coupling.    Note in line 4-5 and we saying we want to import the value for Message.  Here I am showing doing it by type (string).. because basic types such as strings might be pretty common, consider using a named import such as [Import(“Message”)]



   1: class Program
   2: {
   3:  
   4:     [Import]
   5:     public string Message { get; set; }
   6:  
   7:     public void Run()
   8:     {
   9:        // SimpleHello hello = new SimpleHello();
  10:         //Message = hello.Message;
  11:  
  12:         Console.WriteLine(Message);
  13:         Console.ReadKey();
  14:     }

Now in the SimpleHello class we need to export the Message property.  This tells the system it can be used to satisfy requirements.    Notice line 3 and 4 and am marking it with an Export attribute..  Again, this exports it by type (string in this case).  As with above, you might want to do it with an explicit name for a more real world example [Export(“Message”)]



   1: public class SimpleHello 
   2: {
   3:     [Export]
   4:     public string Message
   5:     {
   6:         get
   7:         {
   8:             return “hello world!!”;
   9:         }
  10:     }
  11: }

Now we need to tell MEF to wire these up for us.



   1: public void Run()
   2: {
   3:     //SimpleHello hello = new SimpleHello();
   4:     //Message = hello.Message;
   5:     var catalog = new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());
   6:     var container = new CompositionContainer(catalog.CreateResolver());
   7:     container.AddPart(this);
   8:     container.Compose();
   9:  
  10:  
  11:     Console.WriteLine(Message);
  12:     Console.ReadKey();
  13: }

In line 5, we create a catalog — that tells MEF where to look for imports and exports.  In this case, we are saying the currently running assembly.  There are tons of different parts catalogs, we will look at some later and you can of course build your own.


in line 6, we create a Composition container– this is effectively the soup that all the different parts will be wired up together.


In line 7, we add this instance of Program to the container so that its dependencies get wired up.


In line 8, we do the compose magic.  this is where the Message property of Program gets set. 


Notice, in this case the wire up is done by matching types (String to String)… clearly that isn’t always the right way, we will look at other ways to wire up later.


Run it and you get the expected output of “hello world!”.


Now let’s add another message, just to be a little more fun… 



   1: public class MoreMessages
   2: {
   3:     [Export]
   4:     public string FunMessage
   5:     {
   6:         get
   7:         {
   8:             return “This is getting fun!”;
   9:         }
  10:     }
  11: }

Now run.. It blows up!  Why?  Well, let’s look at the exception:



System.ComponentModel.Composition.CompositionException  Error : Multiple exports were found that match the constraint ‘(composableItem.ContractName = \”System.String\”)’. The import for this contract requires a single export only.”


From the error it looks like we provided too many ways to satisfy the Import… MEF didn’t know which one to pick.  Of course you can programmatically get in there and help, you can also just remove the export from one of the messages… but more fun, you can actually tell MEF you are able to deal with zero or more results.  Change the Message property of Program as follows:



   1: [Import]
   2: public IEnumerable<string> Messages { get; set; }

Notice we changed the return type to be a collection of strings rather than just one string.


Now change the usage code slightly and we get:



   1: class Program
   2: {
   3:  
   4:     [Import]
   5:     public IEnumerable<string> Messages { get; set; }
   6:  
   7:     public void Run()
   8:     {
   9:         //SimpleHello hello = new SimpleHello();
  10:         //Message = hello.Message;
  11:         var catalog = new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());
  12:         var container = new CompositionContainer(catalog.CreateResolver());
  13:         container.AddPart(this);
  14:         container.Compose();
  15:  
  16:         foreach (var s in Messages)
  17:         {
  18:             Console.WriteLine(s);
  19:         }
  20:  
  21:     
  22:         Console.ReadKey();
  23:     }

image


Wow — we get both messages!  Pretty cool…


More Value of MEF


Ok, I think we can all agree that we added a little complexity if all we were going to do is factor what was in the same assembly. MEF really shines when you have separate independent groups working on different components.  By definition these are often in different assemblies with cross no dependencies.  To show how MEF supports this, let’s add a new Class Library project to our solution.    Call it ExternalMessages and add a reference to the System.ComponentModel.Composition.dll assembly.


Add the following class.



   1: using System;
   2: using System.ComponentModel.Composition;
   3:  
   4: public class Class1
   5: {
   6:     [Export]
   7:     public string Message
   8:     {
   9:         get
  10:         {
  11:             return “I am starting to get it…”;
  12:         }
  13:     }
  14: }

Now we need to wire up this class into the catalog…    Notice in line 6, we change the catalog to look in a directory for the parts… 



   1: public void Run()
   2:  {
   3:      //SimpleHello hello = new SimpleHello();
   4:      //Message = hello.Message;
   5:      var catalog = new DirectoryPartCatalog(@”..\..\..\ExternalMessages\bin\Debug”);
   6:          // new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());
   7:      var container = new CompositionContainer(catalog.CreateResolver());
   8:      container.AddPart(this);
   9:      container.Compose();
  10:  
  11:      foreach (var s in Messages)
  12:      {
  13:          Console.WriteLine(s);
  14:      }
  15:  
  16:  
  17:      Console.ReadKey();
  18:  }

Note: DirectoryPartCatalog also supports relative paths that will look for a path under the current AppDomain.CurrentDomain.BaseDirectory.  For example:
new DirectoryPartCatalog(@โ€.\extensions\โ€);


Run it and we get our new message! 


Cool, but we lost our old messages, and I kind of liked them too…  Well, luckily, we have an aggregate part catalog that can take parts from several sources.



   1: public void Run()
   2:  {
   3:      //SimpleHello hello = new SimpleHello();
   4:      //Message = hello.Message;
   5:      var catalog = new AggregatingComposablePartCatalog();
   6:         catalog.Catalogs.Add (new DirectoryPartCatalog(@”..\..\..\ExternalMessages\bin\Debug”));
   7:         catalog.Catalogs.Add (new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()));
   8:      var container = new CompositionContainer(catalog.CreateResolver());
   9:      container.AddPart(this);
  10:      container.Compose();

Pretty cool, we now get all the messages!


image


Finally, just to bring up the point here… I created a bunch of different assemblies that exported Messages… All I need to do is point the catalog at them and go. 


image



   1: public void Run()
   2: {
   3:     //SimpleHello hello = new SimpleHello();
   4:     //Message = hello.Message;
   5:     var catalog = new AggregatingComposablePartCatalog();
   6:        catalog.Catalogs.Add (new DirectoryPartCatalog(@”..\..\..\ExternalMessages\bin\Debug”));
   7:        catalog.Catalogs.Add(new DirectoryPartCatalog(@”..\..\..\ExtraMessages”));
   8:        catalog.Catalogs.Add (new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()));
   9:     var container = new CompositionContainer(catalog.CreateResolver());
  10:     container.AddPart(this);
  11:     container.Compose();
  12:  

See where I added them in line 7..    Now just copy the assemblies into this directory and they become available for this program to use! Notice how I don’t need to change any of the logic of the core program as I add more and more extensions. 


image


Taking MEF to the Next Level


Above I showed the simplest scenario… let’s get a bit more powerful.  If you pick apart the main program looking for tight coupling, that Console.WriteLine() will really stand out.. What if you want to log to a file, call a web service or print to HTML or WPF?   Tightly coupling to the Console does not make that easy.  How can we use the seperation of concerns principle and MEF to get rid of this tight coupling? 


First, we need to define an interface that describes the contract for outputting strings.  To ensure correct dependency management go ahead and create a new Library project called SharedLibrary, add this interface and reference this project from each of the other team projects. 



   1: namespace SharedLibrary
   2: {
   3:     public interface IOutputString
   4:     {
   5:         void OutputStringToConsole(string value);
   6:     }
   7: }

Now, back in the main program we can factor out the Console.WriteLine ()…



   1: class Program
   2: {
   3:     [Import]
   4:     public IEnumerable<string> Messages { get; set; }
   5:  
   6:     [Import]
   7:     public IOutputString Out { get; set; }
   8:  
   9:     public void Run()
  10:     {
  11:         //SimpleHello hello = new SimpleHello();
  12:         //Message = hello.Message;
  13:         var catalog = new AggregatingComposablePartCatalog();
  14:            catalog.Catalogs.Add (new DirectoryPartCatalog(@”..\..\..\ExternalMessages\bin\Debug”));
  15:            catalog.Catalogs.Add(new DirectoryPartCatalog(@”..\..\..\ExtraMessages”));
  16:            catalog.Catalogs.Add (new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()));
  17:         var container = new CompositionContainer(catalog.CreateResolver());
  18:         container.AddPart(this);
  19:         container.Compose();
  20:  
  21:         foreach (var s in Messages)
  22:         {
  23:             Out.OutputString(s);
  24:         }
  25:  
  26:     
  27:         Console.ReadKey();
  28:     }

In line 6-7 we define Out and in line 23 we change from Console.WriteLine() to Out.OutputString().


Now in External Messages project add the following class



   1: [Export(typeof(IOutputString))]
   2: public class Class1 : IOutputString
   3: {
   4:     public void OutputString(string value)
   5:     {
   6:         Console.WriteLine(“Output=” + value);
   7:     }
   8:  
   9:     

Notice here we are explicitly saying the expert type to be that shared interface.  Now when we run it we get:


image


To make things more interesting, lets add another implementation of IOutputString that is a bit more creative.



   1: [Export(typeof(IOutputString))]
   2: public class ReverseOutputter : IOutputString
   3: {
   4:  
   5:     public void OutputString(string value)
   6:     {
   7:         foreach (var s in value.Split().Reverse())
   8:         {
   9:             Console.ForegroundColor = (ConsoleColor)(s.Length % 10);
  10:             Console.Write(s + ” “);
  11:         }
  12:         Console.WriteLine();
  13:     }
  14: }

Just running this now would give us an error right, because we told MEF we wanted exactly one IOutputString… if we change our code to work with multiple we get more fun!  In line 7 we changed to request a set of IOutputStrings and in line 19 we changed to loop through all the output devices. 



   1: class Program
   2: {
   3:     [Import]
   4:     public IEnumerable<string> Messages { get; set; }
   5:  
   6:     [Import]
   7:     public IEnumerable<IOutputString> OutputSet { get; set; }
   8:  
   9:     public void Run()
  10:     {
  11:         var catalog = new AggregatingComposablePartCatalog();
  12:            catalog.Catalogs.Add (new DirectoryPartCatalog(@”..\..\..\ExternalMessages\bin\Debug”));
  13:            catalog.Catalogs.Add(new DirectoryPartCatalog(@”..\..\..\ExtraMessages”));
  14:            catalog.Catalogs.Add (new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()));
  15:         var container = new CompositionContainer(catalog.CreateResolver());
  16:         container.AddPart(this);
  17:         container.Compose();
  18:  
  19:         foreach (var Out in OutputSet)
  20:         {
  21:             foreach (var s in Messages)
  22:             {
  23:                 Out.OutputString(s);
  24:             }
  25:         }
  26:  
  27:     
  28:         Console.ReadKey();
  29:     }

Now when we run it we get all our messages in all our outputs..


image


Now the only real logic in our main is the nested foreach loops.  We may very well like to change that in the future as well… so let’s see if we can abstract that out using exactly the same techniques we have talked about already. 



   1: class Program
   2: {
   3:     [Import]
   4:     public IEnumerable<string> Messages { get; set; }
   5:  
   6:     [Import]
   7:     public IEnumerable<IOutputString> OutputSet { get; set; }
   8:  
   9:     [Import(“OutputMessages”)]
  10:     public Action<IEnumerable<IOutputString>, IEnumerable<string>> OutputMessages { get; set; }
  11:  
  12:     public void Run()
  13:     {
  14:         var catalog = new AggregatingComposablePartCatalog();
  15:            catalog.Catalogs.Add (new DirectoryPartCatalog(@”..\..\..\ExternalMessages\bin\Debug”));
  16:            catalog.Catalogs.Add(new DirectoryPartCatalog(@”..\..\..\ExtraMessages”));
  17:            catalog.Catalogs.Add (new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()));
  18:         var container = new CompositionContainer(catalog.CreateResolver());
  19:         container.AddPart(this);
  20:         container.Compose();
  21:  
  22:  
  23:         OutputMessages(OutputSet, Messages); 
  24:         
  25:     }

First, in line 9-10 we define an Action that can do the output… and in line 23 we remove our nested foreach loops and replace it with a call to this method.  Now all we have in our Main is effectively wiring up components.  Very loosely coupled!


Now let’s add an option for how the messages are outputted.   It would be very easy to define a config file option for selecting these and returning the correct one.  Notice that MEF knows that this method follows the contract of the Action delegate above, so it does all the wireup for us. 



   1: [Export(“OutputMessages”)]
   2: public void OutputByMessage(IEnumerable<IOutputString> outputSet, IEnumerable<string> messages)
   3: {
   4:     foreach (var s in messages)
   5:     {
   6:         foreach (var Out in outputSet)   
   7:         {
   8:             Out.OutputString(s);
   9:         }
  10:     }
  11:     Console.ReadKey();
  12: }

I would love to hear what you think?  Can you think of usage for MEF in your applications?    I’d also love for you to grab the final sample and see how many different ways you can extend it..  Here is the final working sample.  Enjoy!

Comments (35)

  1. joewood says:

    Very nice tutorial.

    How about an option to dynamically bind.  So if you drop a new DLL in the directory it would be added into the container and bound at runtime – without having to restart.

    Also like to see some options for synchronous/asynchronous calling patterns in outgoing interfaces where there’s more than one target.  Maybe an opportunity to incorporate WF.

  2. Jason Olson says:

    Hey Joe, regarding dynamically binding… while Brad didn’t show it here, it is supported in the current methods via "rebinding." The reason the app needs to be restarted here in Brad’s demo is he outputs the messages and then effectively ends the app.

  3. Will says:

    I’d love to see one of these frameworks move the linking logic into a much lower level in the type resolution call stack.  

    This is great and all, but what happens when a type is resolved from within code you can’t control?  For instance, during xaml or xml deserialization.  You can’t rewrite the serializers to use the MEF to identify, load and compose types that aren’t known at compile time or within any loaded assemblies….

  4. iCe says:

    I see great oportunity within the logging app block to greatly extend the loggers you want without providing any explicit implementation.

  5. Robert says:

    I have a few questions about MEF: What about System.Addin? Couldn´t that be done with it? What is the difference between MEF and System.Addin?

  6. joewood says:

    Thanks Jason.

    Also I would ask how this works with start-up configuration – like IoC containers.

  7. Hank says:

    I have searched the NET and I should say I have not come across an article like this which is so easy to understand and learn the concepts.

    cheers

  8. gblock says:

    @Robert, Krys has a good article on this here. http://blogs.msdn.com/kcwalina/archive/2008/06/13/MAFMEF.aspx

    The bits that he wrote the article based on are old, however the principle still stands. MAF is primarily focused on add-in activation and isolation. MEF is concerned with discovery and compostion of clr-types, which includes types activated through MAF. There is some overlap though, however in the places where they overlap, the functionality supports the primary goals of each framework.

  9. The past few weeks, the momentum has picked up around samples using MEF. In my last post I mentioned

  10. Brad Abrams has a post on his blog Simple Introduction to Extensible Applications with the Managed Extensions

  11. Brad Abrams can always be relied upon for a great post – and the latest whizzy thing to come from Microsoft

  12. Brad Abrams can always be relied upon for a great post – and the latest whizzy thing to come from Microsoft

  13. BorekB says:

    This is great introduction. There might be a small typo – IOutputString interface should contain OutputString() instead of OutputStringToConsole().

  14. You’ve been kicked (a good thing) – Trackback from DotNetKicks.com

  15. Ganesh says:

    Excellent KISS approach.

    I have only one doubt,

    The second example looks like the export happens by type rather than the property. This would mean any dll loaded by a catalog if it has a exported string it will show that as a message.

    The other thing is what someone had already said, this whole idea of loading dlls by reflection should happen at a very low level.

    There are other issues with the MEF approach and calls for enhancements. For example

    1) securing a class to be loaded based on authentication,

    2) getting the other dlls that are used by the one loaded is another I can think of.

    3) Loading dlls from different sources.

  16. joshka says:

    The feed item for this is borked and loses formatting.

  17. Dave R. says:

    Thank you for the post. I have a few queries:

    1) Will MEF be a separate download with source, a DLL-only download, or will it become part of the Framework?

    2) It seems a little like an ‘everything including the kitchen sink’ approach. For simple client-side apps that, say, just want to dynamically load extensions, this is going to add quite a lot to download sizes. This is what stopped me from using things like Application Blocks in the past – they seem focused on the Enterprise rather than the more casual developer. Can we pick and choose from the catalogs should we only want to use one type?

    3) You mention that there are many different catalog types. If this is the case, wouldn’t it be preferable to rely on the container constructor to recognise both the type and whether it’s being passed a single container or a List of them? It seems a bit tortuous to have to setup an AggregatingComposablePartCatalog, add other catalogs to that, then pass it to the container. I think it would be less hassle for devs if we could just create a container without having to be explicit about the catalogs. Also could there be an overloaded Catalog constructor instead of all the separate types? For example:

    // ‘Catalog’ instead of ‘AttributedAssemblyPartCatalog’

    var myCatalog = new Catalog(Assembly.GetExecutingAssembly());

    var container = new CompositionContainer(myCatalog);

    container.AddPart(this);

    or

    var cats = new List<Catalog>() { new Catalog(Assembly.GetExecutingAssembly()), new Catalog("C:\My Types") };

    var container = new container(cats);

    container.AddPart(this);

    3) Hasn’t this been covered by other extensibility frameworks?

    Sorry if this seems a little negative. I do look forward to having a play with the release and reading about it further.

  18. Ganesh says:

    In the example under Taking MEF to next level, the Interface is well known to the application as well as the MEF’d dll. This would mean that a dynamic loading will only be possible for those dlls that support that interface.

    So from that example it looks like, an application implementing MEF should be well aware of what interface(s) it is going to implement. hmmmm.,,,,,,

  19. How do AppDomains fit into this? Or do they at all?

  20. Ganesh says:

    for single applications where the classes are in the same assembly, won’t the code below be easier to implement?

    <code>

    private ArrayList getTasks()

    {

    ArrayList allTasks = new ArrayList();

    Assembly assembly = Assembly.Load(Assembly.GetCallingAssembly().FullName );

    foreach (Type type in assembly.GetTypes())

    {

    if (type.IsClass == true)

    {

    // create an instance of the object

    try

    {

    object taskable = type.GetInterface ("ITask");

    if (taskable != null)

    {

    object ClassObj = Activator.CreateInstance(type);

    if (ClassObj is ITask )

    {

    allTasks.Add((ITask)ClassObj);

    }

    }

    }

    catch(MissingMethodException ex)

    {

    Console.WriteLine (ex.Message);

    }

    }

    }

    return allTasks;

    }

    </code>

    where ITask is the interface.

    The above code will instantiate all classes in the executing assembly that implements ITask

    for loading from other assemblies, one can use "LoadFile" or "LoadFrom" method of Assembly class

    This will work in all versions of .net framework in my opinion

    And in the main logic , all one has to do is to,

    ArrayList taskStack = getTasks();

    foreach(ITask aTask in taskStack)

    {

    aTask.execute ();

    }

    Doesn’t the code do the same thing what MEF does?

  21. gblock says:

    @Dave

    1. MEF will continue to ship on Codeplex for now, but will be rolled into the framework.

    2. Catalogs load things on demand. So if all you are asking for is a logger in a single assembly, ONLY that assembly will load, and only upon instantiation. If that logger has a dependency on another assembly, then it will load as well.

    3. Good points on the catalog. We are working on syntactic sugar to do this. One apporach is have a hosting api that contains all the common things you need to do. For example it would accept a list of folders which behind the scenes will end up having a DirectoryPartCatalog created. The api will be a helper which creates the resolver and catalogs behind the scenes allowing the client to simply write one line of code. Does this make sense?

    Thanks for the feedback, keep it coming!

    Regards

    Glenn

  22. gblock says:

    @chrisplasun

    MEF doesn’t handle isolation as this is what System.Addin is for. MEF can work with System.Addin to allow it activate parts in a separate app domain / process. We don’t provide the plumbing for this out of the box, but our model supports it.

    Thanks

  23. Jomit says:

    Excellent Brad,

    Simple & Effective. The last example was more interesting.

    Thanks

    Jomit

  24. GHA says:

    Simple Introduction to Extensible Applications with the Managed Extensions Framework

  25. Dave R. says:

    Hi Glenn,

    Many thanks for the response. The ‘syntactic sugar’ you mention is exactly the sort of thing that sounds very useful, especially if it shields us mere mortals from having to do a lot of the plumbing for simple scenarios.

    It would be fantastic if you could share some of the API mock-ups with us – I’m passionate about this after reading Brad’s FDG book ๐Ÿ˜‰

  26. ใ€ๅŽŸๆ–‡ๅœฐๅ€ใ€‘ Simple Introduction to Extensible Applications with the Managed Extensions Framework ใ€ๅŽŸๆ–‡ๅ‘่กจๆ—ฅๆœŸใ€‘

  27. Richie Scott says:

    Excellent blog Brad – can you tell me where you think MEF fits with Unity, replace or complement?

    Thanks

  28. Cleve Littlefield says:

    I would love to see another article under the same writing approach that compares MEF to System.AddIn (as one other person commented) and/or any generic IoC container like StructureMap, Unity, Castle Windsor…

    What are the overlaps, dependencies, differences?

  29. hi there, also I’ve talked a little bit in this blog on practical writing of Add-in-based applications,

  30. Glenn Block says:

    Hi Dave

    Here is a snippet which we’ve been toying with just to illustrate the thinking

    In your Main method of your program you would do something like:

    static void Main(args[] string) {

     var CompositionHost = new CompositionHost(".");

     CompositionHost.Run(args)

    }

    this would then import an IApplicationStart that has a Start method and would kick off composition.

    [Export(typeof(IApplicationStart))

    public class ApplicationStart : IApplicationStart

    {

     void Run(string[] args){}

     [Import]

     ISomeService Service{get;set;}

    }

    The host class would manage the container behind the scenes, automatically import the App Start and execute it. Having the App Start part imported would being the composition satisfying any it’s imports, it’s imports imports, and so on.

    Because App Start is an interface, you can host it wherever you like for example in an App.Xaml.cs, or the Main for a winform app, or even in a Web Service host.

    Does this seem useful? Any feedback would be appreciated.

  31. Guy kolbis says:

    MEF stands for &quot; M anaged E xtensions F ramework&quot;. The idea behinds it is to allow reuse and

  32. The Managed Extensibility Framework (MEF) is a new feature of .NET 4 (and will work on 3.5 as well) that

  33. The Managed Extensibility Framework (MEF) is a new feature of .NET 4 (and will work on 3.5 as well) that

  34. Bill Sithiro says:

    Good programmers have been implementing similar approaches to this since like… forever! Not that I don’t like it, I think it would be great if this becomes mainstream in the .NET world having a common way of implementing plug-in/add-in/extentending architecture. But, I have a question, what if the class with the color text output that came later could apply the same behaviour to the earlier monochrome ones. How hard would that be to implement?

Skip to main content