Posted by: Zeeshan Amjad | March 29, 2012

PlugIn Lifetime Pattern


We already saw one example of using DirectoryCatalog with ImportMany attribute to load multiple DLL at run time using MEF here. This is a good starting point to develop plug in architecture. But when developing plug in architecture we have to consider few more things and one such thing is the life time of the plug in.

Let’s take a look at this from example. Suppose we define an interface of a plug in and all the plug in suppose to implement that interface and use MEF to load them at run time as discussed in the example here. But there may be one problem in this approach. Suppose we want to make one plug in that is based on another. In other words we want to use the functionality of one plug in in another then how can we do it? We are not sure the order of loading the plug ins so we can’t write a code that guarantee us that the other plug in is already loaded.

We can solve this problem by refactoring a code little bit. We can introduce a method initialized that is suppose to call after all the plug ins are loaded in the memory. Let’s see the simple interface for this.

Code Snippet
namespace PlugInContainer
{
    public interface IPlugIn
    {
        void Start();
        void Initialized();
        void Destory();
    }
}

 

Now the important thing is that, container is suppose to call the Start method of all the plug ins before calling the initialized method. Let’s take a look at the container code first.

Code Snippet
public Container()
{
    DirectoryCatalog catalog = new DirectoryCatalog(".");
    CompositionContainer container = new CompositionContainer(catalog);
    CompositionBatch batch = new CompositionBatch();
    batch.AddPart(this);
    container.Compose(batch);

    // doesn't implement PlugIn Lifetime Pattern
    foreach (IPlugIn plugin in PlugIns)
    {
        plugin.Start();
        plugin.Initialized();
    }
}

 

In the code above we are calling Start and Initialized method of each plug in before moving to another plug in, so we can’t write a plug in that depends on each other. Let’s change a code little bit.

Code Snippet
public Container()
{
    DirectoryCatalog catalog = new DirectoryCatalog(".");
    CompositionContainer container = new CompositionContainer(catalog);
    CompositionBatch batch = new CompositionBatch();
    batch.AddPart(this);
    container.Compose(batch);

    // implement PlugIn Lifetime Pattern
    foreach (IPlugIn plugin in PlugIns)
    {
        plugin.Start();
    }

    foreach (IPlugIn plugin in PlugIns)
    {
        plugin.Initialized();
    }
}

 

Here we are calling the Start method of all the plug ins then call Initialized method. This is so common and very well used technique that even Windows SDK implement this using Windows Messageas, MFC implements this using virtual functions and Windows Form, WPF implements this using overridden methods or events. Here is a simple diagram to explain this pattern.

PlugInLifeTimePattern

 

This diagram explain that we are suppose to Start method of all the plug ins before calling Initialized method. In other words we are  suppose to call methods in vertical order not horizontal order. Now if we write a dependency code in Initialized method then we are sure that all the plug ins are already loaded in the memory.

Here is complete code of our container class.

Code Snippet
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

namespace PlugInContainer
{
    public class Container
    {
        [ImportMany(typeof(IPlugIn))]
        public IEnumerable<IPlugIn> PlugIns
        { get; set; }

        public Container()
        {
            DirectoryCatalog catalog = new DirectoryCatalog(".");
            CompositionContainer container = new CompositionContainer(catalog);
            CompositionBatch batch = new CompositionBatch();
            batch.AddPart(this);
            container.Compose(batch);

            // implement PlugIn Lifetime Pattern
            foreach (IPlugIn plugin in PlugIns)
            {
                plugin.Start();
            }

            foreach (IPlugIn plugin in PlugIns)
            {
                plugin.Initialized();
            }
        }
    }
}

 

Here is the implementation of our first plug in.

Code Snippet
using System;
using System.ComponentModel.Composition;
using PlugInContainer;

namespace FirstPlugIn
{
    [Export(typeof(IPlugIn))]
    public class FirstPlugInClass : IPlugIn
    {
        public void Start()
        {
            Console.WriteLine("FirstPlugInClass.Start");
        }

        public void Initialized()
        {
            Console.WriteLine("FirstPlugInClass.Initilized");
        }

        public void Destory()
        {
            Console.WriteLine("FirstPlugInClass.Destory");
        }
    }
}

 

The second plug in is very similar to the first one to just show the proof of concept.

Code Snippet
using System;
using System.ComponentModel.Composition;
using PlugInContainer;

namespace SecondPlugIn
{
    [Export(typeof(IPlugIn))]
    public class SecondPlugInClass : IPlugIn
    {
        public void Start()
        {
            Console.WriteLine("SecondPlugInClass.Start");
        }

        public void Initialized()
        {
            Console.WriteLine("SecondPlugInClass.Initilized");
        }

        public void Destory()
        {
            Console.WriteLine("SecondPlugInClass.Destory");
        }
    }
}

 

And here is a code of our main client program.

Code Snippet
using PlugInContainer;

namespace PlugInClient
{
    class Program
    {
        static void Main(string[] args)
        {
            Container container = new Container();
        }
    }
}

 

This is the output of the program.

FirstPlugInClass.Start
SecondPlugInClass.Start
FirstPlugInClass.Initilized
SecondPlugInClass.Initilized

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: