Creating a Pluggable Application Without Any External Dependencies on 3rd-party Libraries

Creating a Pluggable Application Without Any External Dependencies on 3rd-party Libraries

A complete example of making a pluggable application without any external dependencies on 3rd-party libraries.

To achieve that, we will need three different projects, I'm starting out from the engine to the application that will eventually host it.

1. PluggableApplication.Interface

This project provides two things:

  1. The interfaces that plugins can implement 
  2. The engine that responsible to discover and load plugins.

So the first thing you need to do is define the interface that plugins will implement.

public interface IPluginBase
{
    string Name { get; }
    string Version { get; }
}

Next, we're going to define a new interface that inherits from IPluginBase and we will use it to compute two numbers.

public interface IMath : IPluginBase
{
    int Compute(int arg1, int arg2);
}

Finally, we need to implement the engine that will discover the plugins based on some rule in this case the rule is any class that implements IPluginBase.

namespace PluggableApplication.Interface
{
    using System;
    using System.IO;
    using System.Reflection;
    using System.Linq;
 
    public static class Plugin
    {
        public static T CreatePlugin<T>(string file) {
 
            T plugin = default(T);
             
            Type pluginType = null;
 
            if(File.Exists(file))
            {
                Assembly asm = Assembly.LoadFile(file);
 
                if(asm != null)
                {
                    for(int i = 0; i < asm.GetTypes().Length; i++)
                    {
                        Type type = (Type)asm.GetTypes().GetValue(i);
                         
                        if (IsImplementationOf(type, typeof(IPluginBase)))
                        {
                            plugin = (T)Activator.CreateInstance(type);
                        }
                    }
                }
            }
 
            return plugin;
        }
         
        private static bool IsImplementationOf(Type type, Type @interface)
        {
            Type[] interfaces = type.GetInterfaces();
 
            return interfaces.Any(current => IsSubtypeOf(ref current, @interface));
        }
 
        private static bool IsSubtypeOf(ref Type a, Type b)
        {
            if (a == b)
            {
                return true;
            }
 
            if (a.IsGenericType)
            {
                a = a.GetGenericTypeDefinition();
 
                if (a == b)
                {
                    return true;
                }
            }
 
            return false;
        }
    }
}

2. PluggableApplication.Plugin

We will use this project to create our first plugin which will take two numbers and multiply it.

class Math  : IMath
{
    public string Name {
        get { return "Math"; }
    }
 
    public string Version {
        get { return "1.0.0.0"; }
    }
 
    public int Compute(int arg1, int arg2) {
        return arg1 * arg2;
    }
}

3. PluggableApplication.Host

This project will use the engine to execute the plugin and print the results.

namespace PluggableApplication.Host
{
    using System;
 
    using PluggableApplication.Interface;
 
    class Program
    {
        static void Main(string[] args) {
            string filePath = Environment.CurrentDirectory + @"\PluggableApplication.Plugin.dll";
 
            IMath math = Plugin.CreatePlugin<IMath>(filePath);
 
            Console.WriteLine();
 
            if(math != null)
            {
                Console.Write(" Input the 1st number to compute: ");
                int arg1 = Convert.ToInt32(Console.ReadLine());
 
                Console.Write(" Input the 2nd number to compute: ");
                int arg2 = Convert.ToInt32(Console.ReadLine());
 
                Console.WriteLine();
                Console.WriteLine(" Results: " + math.Compute(arg1, arg2));
            }
            else
            {
                Console.WriteLine(" No plugins were found.");
            }
 
            Console.ReadKey(true);
        }
    }
}


Leave a Comment
  • Please add 6 and 2 and type the answer here:
  • Post
Wiki - Revision Comment List(Revision Comment)
Sort by: Published Date | Most Recent | Most Useful
Comments
  • Ed Price - MSFT edited Revision 1. Comment: Title casing

Page 1 of 1 (1 items)
Wikis - Comment List
Sort by: Published Date | Most Recent | Most Useful
Posting comments is temporarily disabled until 10:00am PST on Saturday, December 14th. Thank you for your patience.
Comments
  • Ed Price - MSFT edited Revision 1. Comment: Title casing

  • very good  ;)

Page 1 of 1 (2 items)