composite application

How to create a plug in using C# .NET (4.0) and MEF


Hello,

Long time ago I wrote my approach of how to write a plugin (add in) using Microsoft Unity (http://unity.codeplex.com/). In my old approach (https://hmadrigal.wordpress.com/2010/03/28/writing-a-plug-in/) was using the unity.config file to load dynamically the plugins. Certainly the major issue with this approach it’s that you will have to update your unity.config file every time you add a new plugin.

As usual there is a code sample of all this at:
https://github.com/hmadrigal/playground-dotnet/tree/master/MsDotNet.PluginWithMEF The code runs in MonoDevelop as well as in Visual Studio.

On this post I’ll explain how to easily use Microsoft Extensibility Framework (MEF) http://msdn.microsoft.com/en-us/library/dd460648.aspx to load plugins from a directory. Additionally MEF is a framework to create plugins and extensible applications, so it supports more operations other than loading types from external assemblies.

The problem

I want to load different language implementations provided in different assemblies. So, each DLL might (or might not) contain an implementation of a supported language. Moreover, the assemblies can be implemented by third party members, so I cannot binding them into my project at compile time.

The Solution

Defining what on my application needs to be extensible
Define a common contract in order to identify a class which provided a supported language. Moreover all the “extensible” portion of your application should be encapsulated into a simple assembly that could be redistributed to other developers who wants to implement the plugin.
BTW, when implementing plug ins, it’s normal to define a contract (or interface) which defines the required functionality.I’ll be using the word “part” when I’m talking about contract or interfaces.
The project MefAddIns.Extensibility defines an interface which can be used to provide a supported language.

namespace MefAddIns.Extensibility
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    /// <summary>
    /// Defines the functionality that third parties have to implement for my language plug in
    /// </summary>
    public interface ISupportedLanguage
    {
        string Author { get; }
        string Version { get; }
        string Description { get; }
        string Name { get; }
    }
}

Implementing the plug in
Now it’s the time to provide implementation of supported languages. Each project of MefAddIns.Language.English, MefAddIns.Language.Japanese and MefAddIns.Language.Spanish provides at least one implementation for the interface ISupportedLanguage. These projects could be developed internally or by third party people. An example of this implementation is:

namespace MefAddIns.Language.English
{
    using MefAddIns.Extensibility;
    using System.ComponentModel.Composition;

    /// <summary>
    /// Provides an implementation of a supported language by implementing ISupportedLanguage.
    /// Moreover it uses Export attribute to make it available thru MEF framework.
    /// </summary>
    [Export(typeof(ISupportedLanguage))]
    public class EnglishLanguage : ISupportedLanguage
    {
        public string Author
        {
            get { return @"Herberth Madrigal"; }
        }
        public string Version
        {
            get { return @"EN-US.1.0.0"; }
        }
        public string Description
        {
            get { return "This is the English language pack."; }
        }
        public string Name
        {
            get { return @"English"; }
        }
    }
}

Please note that the attribute Export indicates to MEF framework that the class EnglishLanguage can be used when a ISupportedLanguage is requested. In other words, if any other application is looking for a part ISupportedLanguage then MEF framework will suggest EnglishLanguage. In further steps we are going to create a MEF catalog which is the mechanism to associate exported parts with the members which need to import parts.

Defining the parts that my application needs to import
The simplest way of doing this with MEF is by using the import attribute. On this case I’ll be using ImportMany because of I’ll be expecting many (0 or more) implementations of the ISupportedLanguage interface. For example:

namespace MefAddIns.Terminal
{
    using MefAddIns.Extensibility;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;

    public class Bootstrapper
    {
        /// <summary>
        /// Holds a list of all the valid languages for this application
        /// </summary>
        [ImportMany]
        public IEnumerable<ISupportedLanguage> Languages { get; set; }

    }
}

Composing your objects by using (MEF) catalogs
Before getting into details I’ll like to point out some concepts:

Part: It’s the portion of our code that can be exported or imported.
Export: It’s the fact of indicating that a portion of our code is available and it fits a set of traits. E.g. EnglishLanguage implements the ISupportedLanguage Interface, thus I can add the attribute Export(typeof(ISupportedLanguage)).
Import: It’s the fact of indicating that a portion of our code requires a part that fits a set of traits. E.g. I need to import a give language, then I define a property of ISupportedLanguage type and set the attribute Import(typeof(ISupportedLanguage)).
Catalog: It a source of Exports and Import definitions. It could be the current execution context or a set of binaries files (such as dlls, exes).
Container: It’s an module which deals with class instantiation. This item uses the catalog when needed in order to create the instances during the composition process.
Composition: It’s the fact of taking an object and making sure that all its needs regarding imports are fulfilled. Certainly this will depends on the catalogs and the export and imports that are being used on the catalog.

Now, that we now more about come MEF concepts. Lets talk more about MEF in our example. MEF detects that some code is Exporting parts, and other code is Importing. The process of loading the parts is made by creating a catalog. There are many ways of creating catalogs, on my example is using a DictionaryCatalog. The DictionaryCatalog uses a directory to look for files, and it creates a catalog with all the exported parts from the assemblies (or files) of the given directory. Finally our application creates an instance of the Bootstrapper class, this instance indicates that it requires all the possible instances of ISupportedLanguages that are into the DictionaryCatalog. Here is a sample of this:

namespace MefAddIns.Terminal
{
    using System.ComponentModel.Composition.Hosting;
    using System.ComponentModel.Composition;
    using System;

    class Program
    {
        static void Main(string[] args)
        {
            var bootStrapper = new Bootstrapper();

            //An aggregate catalog that combines multiple catalogs
            var catalog = new AggregateCatalog();
            //Adds all the parts found in same directory where the application is running!
            var currentPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetAssembly(typeof(Program)).Location);
            catalog.Catalogs.Add(new DirectoryCatalog(currentPath));

            //Create the CompositionContainer with the parts in the catalog
            var _container = new CompositionContainer(catalog);

            //Fill the imports of this object
            try
            {
                _container.ComposeParts(bootStrapper);
            }
            catch (CompositionException compositionException)
            {
                Console.WriteLine(compositionException.ToString());
            }

            //Prints all the languages that were found into the application directory
            var i = 0;
            foreach (var language in bootStrapper.Languages)
            {
                Console.WriteLine("[{0}] {1} by {2}.\n\t{3}\n", language.Version, language.Name, language.Author, language.Description);
                i++;
            }
            Console.WriteLine("It has been found {0} supported languages",i);
            Console.ReadKey();
        }

    }
}

Now that we have all that our application requires, we’re able to run the app and see the following output:

Example of the output where it lists all the supported languages

Hey It’s not printing anything!!!
Ok. There is an additional thing to talk, which it’s not strictly related to MEF. As your might noticed our sample application does not have references to any of the MefAddIns.Language.* Dlls but it’s running code from them. Here is the deal, since our application uses MEF we don’t need to reference directly these DLLS, we just need to copy them into the directory where the DirectoryCatalog is going to look for them. The code sample looks into the directory where the application is running, so we have configured our main csproj to copy the DLLS to the output directory of our main application.
To keep it simple, you can do it in two steps 😉
1) Add the external DLLs into your project. First, Right click on your main project, and click on “Add existing item…”. Look for the DLL, and select “Add as a Link”. The configure the properties of the added file to copy always or copy when newer.
2) Update the csproj file. Right click on your project, and the select “Unload project”. Then once again right click on your project and select “Edit xxxxx.csproj”. This will open the project as an XML file. Look for the added DLL, and replace part of portions of the path for MSBuild variables such as $(Configuration). Note that there are more options to do this, such as using the Copy task from MSBuild (see http://stackoverflow.com/questions/266888/msbuild-copy-output-from-another-project-into-the-output-of-the-current-project ). In our sample this was enough because we are looking for DLLs into the current directory, but depending on your file structure this won’t be recommended.

<ItemGroup>
    <Content Include="
..\MefAddIns.Language.English\bin\$(Configuration)\MefAddIns.Language.English.dll;
..\MefAddIns.Language.Japanese\bin\$(Configuration)\MefAddIns.Language.Japanese.dll;
..\MefAddIns.Language.Spanish\bin\$(Configuration)\MefAddIns.Language.Spanish.dll;">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Visible>false</Visible>
    </Content>
  </ItemGroup>

At last comment, this is the most basic sample of using MEF to create a plugin-based structure. There are more things to consider , e.g. the path where your DLLs are going to be placed or how your main application is going to exchange information with the plugins. MEF has also more options to create extensible applications. Also, it’s important to consider when it’s good to create plugin based architectures rather that tightly coupled apps.

EDIT In my last update I modified the project (csproj) to make it run on MonoDevelop ;-). The major change is that some tasks on MSBuild aren’t available in XBuild. So, the last step which modified the csproject, now looks like:

<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <Content Include="..\MefAddIns.Language.English\bin\Debug\MefAddIns.Language.English.dll">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Visible>False</Visible>
    </Content>
    <Content Include="..\MefAddIns.Language.Japanese\bin\Debug\MefAddIns.Language.Japanese.dll">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Visible>False</Visible>
    </Content>
    <Content Include="..\MefAddIns.Language.Spanish\bin\Debug\MefAddIns.Language.Spanish.dll">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Visible>False</Visible>
    </Content>
  </ItemGroup>
  <ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <Content Include="..\MefAddIns.Language.English\bin\Release\MefAddIns.Language.English.dll">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Visible>False</Visible>
    </Content>
    <Content Include="..\MefAddIns.Language.Japanese\bin\Release\MefAddIns.Language.Japanese.dll">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Visible>False</Visible>
    </Content>
    <Content Include="..\MefAddIns.Language.Spanish\bin\Release\MefAddIns.Language.Spanish.dll">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <Visible>False</Visible>
    </Content>
  </ItemGroup>

The code sample for this application is at:
https://github.com/hmadrigal/playground-dotnet/tree/master/MsDotNet.PluginWithMEF

Best regards,
Herber

Prism break #1: The Composite Application


The beginning

Change is the only constant in software development. However, not all the coding styles are easy to adopt changes, even though we consider that our “the code is very flexible“. For example, lets take a look to the following C#  sample:

var myConn = new SqlConnection(myConnectionString);
// perform some operations using the myConn instance.

At very first sight we might thing it’s flexible enough,… however it’s not as flexible as we might think. The only thing we can change is the connection string ( which only works for Sql Connections). We cannot specify a new data source e.g. MySql, SysBase, or a XML feed. So, is it really flexible?

Through the time developers have managed to hide this dependency by using composition and encapsulation. For example we can hide the fact that we are using an instance of SqlConnection by using composition:

public class Connection
{
   private SqlConnection myConnection;
   public Connection {
      myConnection = new SqlConnection("...");
   }
   // ... more public methods for users of this class
}

This approach seems to solve our dependency problem, however we still kinda of tight to the SqlConnection, we can argue that all the layers build over this Connection class, might depend of the SqlConnection class.

So, in fact if we would like to create tests, we will need to specify a SqlConnection to use our Connection class in middle layers. This might be painful if you consider that you’d like to create unit tests where each test will depend of the connection, instead of having more specific data sources to perform accurate tests.

So, what’s next? Simple, developers has used others ways to make the functionality less dependant of the implementation. A first approach is the pattern Dependency Inversion.Which tries to handle contracts (aka interfaces) instead of the concrete implementation of the contract. So, we can rewrite:

public class User
{
   IConnection _connection;

   public User (IConnection connection) {
      this_connection = connection; //
   }
   // ... public methods that depends on the Connection interface (contract)
}

In the previous example, it’s possible to take advance of the all the functionality provided by the connection without knowing if it’s a SqlConnection, MySqlConnection or even a XmlFile. The functionality is exposed by the contract, and we receive by parameter the implementation that has to be used by the class.  This makes the User class depend on the contract instead of the concrete implementation of the contract.

Certainly this model makes appear a new issue. In a supeior level of our structure the concrete implementation has to be instanciated, and this in fact is what makes our code less flexible.

public class UserView
{
   private IUser _currentUser
   public UserView (IUser currentUser){
      this._currentUser =  currentUser;
   }
   // ... so... where does the concrete implementation of User come from?

There are more patterns that solve the issue of the creation of objects, for example we can provide a class that
handles the instantiation of the objects. For example:

public class TopLevelClass
{
   private IUser _currentUser
   public TopLevelClass {
      this._currentUser = Creator.GetInstance<IUser>();
   }
   // ... more methods
}

In this example, the Creator class knows which concrete implementation of IConnection should used in the instantiation of User. This could be specified in a configuration file, or by code. This process of providing instances and injecting its dependencies is known dependency injection. Currently there are several frameworks that allows users to handle the instantiation of the objects in the application.

So, for changing an implementation for the entire application it might be as easy as change a setting in a configuration file, and provide a concrete implementation.

Prism and Dependency Injection

Composite application uses as Microsoft Unity to implement Dependency Injection. Even though the Unity library is already included with Prism, it’s optional to use it. Also, It’s possible to use other Dependency Injection framework, such as Microsoft Extensibility Framework (aka. MEF) which also is provided by Microsoft.

References:

Tame Your Software Dependencies for More Flexible Apps @ http://msdn.microsoft.com/en-us/magazine/cc337885.aspx

Regards,

Herberth