Tag Archives: ManagedExtensibilityFramework

Using the Managed Extensibility Framework (MEF) to implement a third-party plugin solution. Part 3 – Developing the plugins

Now that my application supports plugins, I’m ready to publish my plugin SDK out for other developers to make use of.  If I take a look in my .\bin\Debug folder for the MyPluginApp project (yes, I’m staying in Debug mode for the purposes of this example) I see the following.

Debug Folder Contents

MyPluginApp.exe of course is my Windows Forms Application executable, but in addition to that there is a file called MyPluginApp.Plugins.dll.  This .dll is the compiled version of the Class Library that I added to my solution in Part 2 named MyPluginApp.Plugins.  This is the .dll that I will need to make available to 3rd party developers (henceforth I will refer to this as my “SDK”).  Along, of course, with some thorough documentation outlining what exactly I am expecting them to implement and what metadata I am expecting.

Now I am going to create a new solution from the perspective of a 3rd party developer who wants to develop a plugin for my application.  I start by creating a new “Class Library” project, because I want my code to compile to a .dll that I can place in the Plugins directory for my application.  I’m going to call my new solution MyPluginApp_StarterPlugins.

Once my new solution and project have been created, I take the MyPluginApp.Plugins.dll file that I downloaded as part of the application developer’s SDK *wink wink* and place it in my project directory.  I then add the file to my project, making sure to set the Build Action to ‘None’ and Copy to Output Directory to ‘Do Not Copy.’  The step of explicitly adding the .dll file to my solution is not required, however I think it adds some clarity to what the purpose of my project is.  Now that I’ve physically gotten the SDK into the appropriate place, I need to add a reference to it within the project.  I do this by adding a reference to the actual .dll file that I just moved into my project’s directory.  Also, just to keep Visual Studio from copying the .dll to my bin\{Debug}{Release} folders, I will set “Copy Local” property of the reference to false.  I also need to add a reference to System.Windows.Forms because my intention is to use MessageBox when my plugins perform their tasks.  Finally, I need to add a reference to System.ComponentModel.Composition in order to gain access to the necessary MEF namespaces.

Project Directory

Project Directory Contents

Solution Explorer Containing File

Solution Explorer View

Reference

Solution Explorer References

I’m going to develop two simple plugins within this project.  The first will be called AdditionPlugin, and will add the two numbers together.  The second will be called MultiplicationPlugin, and will multiply the two numbers together.  These plugins will both impliment the IPlugin interface which we defined in the MyPluginApp.Plugins projects and is available to me as a 3rd party developer within the .dll that I have added to my project.

Now I’m ready to define my first plugin.  First I will create the AdditionPlugin.  I rename the Class1.cs default file to AdditionPlugin.cs and replace its contents with the following:

using System;

using System.ComponentModel.Composition; //MEF namespace for Exporting
using System.Windows.Forms; 

namespace MyPluginApp.Plugins
{
    [Export(typeof(IPlugin))] //**1
    [ExportMetadata("Name", "Addition Plugin")] //**2
    public class AdditionPlugin : IPlugin
    {
        public void HandleNumbers(decimal num1, decimal num2)
        {
            MessageBox.Show(string.Format("{0} + {1} = {2}", num1, num2, num1 + num2), "Addition Plugin");
        }
    }


    
    //**1 - This will allow the CompositionContainer in MyPluginApp know that this class is of type IPlugin, which will be loaded 
    //  when we call .GetExports<IPlugin, IPluginMetaData() in the LoadPlugins() method.

    //**2 - This is how MetaData is exported by the Plugin.  The exported metadata needs to match with the metadata interface we defined in MyPluginApp.
    //  In this case we have only 1 defined field in IPluginMetaData called "Name", so that is the only peice of metadata that we want to export.
}

Now if this plugin is enabled (remember the Checked List Box in MyPluginApp?), its HandleNumbers method will be added to the MyButtonClicked event, which gets Invoked every time the button on my form gets clicked.

Similarly to the AdditionPlugin, I add a new .cs file to the project and name it MultiplicationPlugin.cs.  Here are the contents of that file:

using System;
using System.ComponentModel.Composition; //MEF namespace for Exporting
using System.Windows.Forms;

namespace MyPluginApp.Plugins
{
    [Export(typeof(IPlugin))]
    [ExportMetadata("Name", "Multiplication Plugin")]
    public class MultiplicationPlugin : IPlugin
    {
        public void HandleNumbers(decimal num1, decimal num2)
        {
            MessageBox.Show(string.Format("{0} * {1} = {2}", num1, num2, num1 * num2), "Multiplication Plugin");
        }
    }
}

Now I can build my solution.  After the build is complete, I find the following in MyPluginApp_StarterPlugins bin\Debug folder:

image

MyPluginApp_StarterPlugins.dll needs only to be placed in the \Plugins directory of MyPluginApp prior to MyPluginApp being started up.  Here is what MyPluginApp looks like after I do just that.

MyPluginApp with loaded plugins

Clicking on MyButton at this point still yields the familiar output from before Plugin support was added.

MyPluginApp Output no plugins enabled

Clicking OK on the MessageBox dialog returns me to the application.  Now I change Number 1 to “8,” check both boxes, and then click MyButton.

MyPluginApp Enabled Plugins

MyPluginApp - App Output

MyPluginApp - Addition Plugin Output

MyPluginApp - Multiplication Plugin Output

Unchecking the box next to a plugin prior to clicking MyButton again causes that plugin to become unsubscribed from the event, so its MessageBox no longer pops up.

I’ve certainly only begun to scratch the surface of MEF in this series of posts.  But I hope that this simple tutorial showing a method of developing plugin .dll files completely independently of your original application’s code/solution will be of some value to someone.

I have posted a .zip file containing both complete solutions Here.

Using the Managed Extensibility Framework (MEF) to implement a third-party plugin solution. Part 1–Introduction

I recently started working on a project that would benefit greatly from the ability to support plugins that were developed by someone other than myself or anyone else who necessarily had access to our source code. Having never really done anything like this myself I set off and tried to research it. I found a lot of information about loading compiled .dll files, using reflection and Activator.CreateInstance and so on. Then in the comments of those posts I’d see someone say “Why don’t you use MEF?” and that’s it; no other information.

In a quick nutshell, here’s what Wikipedia has to say about MEF as of August 2014:

Managed Extensibility Framework (MEF) is a component of .NET Framework 4.0 aiming to create lightweight, extensible applications. It allows application developers to discover and use extensions with no configuration required. It also lets extension developers easily encapsulate code and avoid fragile hard dependencies. MEF also allows extensions to be reused across applications. MEF was introduced as a part of .NET 4.0 and Silverlight 4.

Additionally, here is the MSDN page for your reference.

In my research, I found a lot of great examples of using MEF to quickly load external dll files and instantiate the types that they had defined within them. The problem was, all of the examples I found had all of the projects (application and plugins) contained within a single solution. I wanted to know how to enable someone else to take my plugin specification and implement it, without me having to distribute my entire solution to them. I never did find a true tutorial on that aspect of MEF, but I did figure out a way that works and that is the way I am going to present in this series. If anyone happens upon this series and has a better method, I’d be happy to learn from you!

In this series of posts I am going to go through the process of creating a .NET 4.0 Windows Forms application that implements a simple plugin system.  The plugins system will load any available plugins on startup and allow the user to enable/disable them.  I will then create an entirely separate solution that creates some example plugins that can be loaded an used by my original program.  This should simulate the workflow that I would expect a third-party developer to go through to develop plugins for my application.

The series will consist of 3 posts.  The first post, which you are now reading, will serve as the introduction and cover the initial application (without plugin support).  In the second post, I will add plugin handling capabilities to the application, and in the third post I will create a couple sample plugins within their own solution.

I’m going to use Visual Studio 2010 for this project.  I will include zipped archives for both solutions at the end of the series.

To start out, I have created a simple application that allows the user to enter two numbers, then reports back to them what they entered.

Application

The Application

Result of pressing the button

Result of Button Press

And the code for my application

using System;
using System.Windows.Forms;

namespace MyPluginApp
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //the Leave event handler for both text boxes
        private void textNum_Leave(object sender, EventArgs e)
        {
            decimal d;
            var textNum = (TextBox) sender;

            if (!decimal.TryParse(textNum.Text, out d))
            {
                textNum.Text = "5";
            }
        }

        //The KeyDown event handler for both text boxes
        private void txtNum_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyData == Keys.Enter || e.KeyData == Keys.Return)
            {
                btnMyButton.Focus(); //fires the Leave event for the active text box
                btnMyButton.PerformClick();
            }
        }

        //OnClick event handler for the button
        private void btnMyButton_Click(object sender, EventArgs e)
        {
            MessageBox.Show(string.Format("You entered {0} and {1}", txtNum1.Text, txtNum2.Text));
        }
    }
}

This concludes the first post of the series.  In the next post I will add the capability for my application to load and utilize plugins.