Friday, 22 April 2011

How to use MEF with C#

MEF stands for Managed Extensibilty Framework and allows C# developers to developer plug-in architectures for their solutions.

This allows any C# project (WPF, Silverlight, ASP.NET, Winforms, Class Library, etc) to make use of external functionality dynamically at runtime without the need for a hard coded reference.  This is made possible through the use of interfaces and MEF with it’s Import and Export attributes and only takes a few lines of code.

MEF is part of the .NET Framework v4.0 and is being used in future versions of Visual Studio to provide their plug-in model.

Architecture

In our demo the host application, in this instance a console app, will load two plug-ins to provide CalculationServices.  Both will implement a Calculate method accepting two integers and returning an integer.  The first CalculationService will add the two numbers together and the second CalculationService plug-in will multiple the numbers together.

architecture

Coding the Demo

First create a Console application called MefSimpleDemo.exe then add three class libraries to the solution:

  SharedContracts (for our interfaces)

  CalculatorService1 (plug-in)

  CalculatorService2 (plug-in).

The Console Application and SharedContracts projects will need to reference MEF and the our Interfaces so right clcik and add the two references for each project.

MEF is stored within the System.ComponentModel.Composition framework (System.ComponentModel.Composition.DLL).

Add-Mef-Reference

add-ref-shared

In our example the plug-ins will be loaded from a known directory location.  In production you would load this location from a config but for this demo we’ll be hardcoding the location (@”../plugins” folder) in the host and building the output of the plug-ins to the same folder.  To alter the output right click on view properties on both plugins click the “Build” tab and update the “Output Path”:

output-to-plugins

SharedContracts.DLL Class Library

Remove the default Class1.cs file, add a file called ICalculationService.cs and paste in the following code:

NOTE: Notice the (MEF) InheritedExport attribute on the interface, this allows MEF to discover the class within the plugin.

CalculationService1.DLL Class Library


Remove the default Class1.cs file, add a file called Addition.cs and paste in the following code:

 

CalculationService2.DLL Class Library

Remove the default Class1.cs file, add a file called Multiply.cs and paste in the following code:

MefSimpleDemo.EXE Console Application

Add a new file called PluginRepository.cs and paste in the following code:

Finally replace the text in the Program.cs file with the following code:


Your solution should now look like this, notice I’ve removed all redundant references from each of the projects:

Solution-explorer


You are now ready to run the application, press F5 and check out your results:

f5


You can download the source code here: 

http://stevenhollidge.com/blog-source-code/MefSimpleDemo.zip

9 comments:

  1. Good post Steven. I managed to get up and running fairly quickly with this, whereas the tutorial for Mef with Caliburn.Micro didn't really get me anywhere. Cheers.

    ReplyDelete
  2. Good to hear Dave, glad it helped you out.

    ReplyDelete
  3. Thank you Steven,
    it helped me a lot, first time I got the picture
    Thomas

    ReplyDelete
  4. Hi!
    I'm currently studying MEF now and I get how it works on plugins that you create in the same solution because its easy to add it as reference.
    My problem is when I create a plugin that is out of the solution and drop its dll in a certain folder. How do i add it as reference so that my application can refresh its content?

    Chris

    ReplyDelete
    Replies
    1. I got it solved. MEF should automatically detect the exports. But I have another problem. How can I export part without using an interface as contract?

      Chris

      Delete
    2. I think you need to implement the Interface in your export part, so that the importing proyect knows how to handle it. But perhaps Steven could clarify this...

      Delete
  5. Hello, great tutorial!

    I tried it, but loading the plugins doesn't work. "CalculationServices" is always empty, but the plugin path is correct. (WinXP, Visual C# 2010 Express).
    What could be the problem?

    Regards

    ReplyDelete
    Replies
    1. It works fine if the project is not within a network drive.

      Delete
  6. What's the purpose of decorating a PluginRepository.CalculationServices with [ImportMany("ICalculationService")] if you assign this value by yourself??

    ReplyDelete