Click here to Skip to main content
14,299,664 members

A Flexible Plugin System

Rate this:
4.98 (25 votes)
Please Sign up or sign in to vote.
4.98 (25 votes)
3 Sep 2008LGPL3
A generic plugin system used to load and manage plugins


As applications grow, they tend to be harder and harder to maintain, despite the fact that most applications are more or less well designed from the start. This is usually because it's very easy to increase coupling when you need to add new features to your application. Plugins are a way to solve this by adding new functionality in small testable DLLs.

This example does not contain a lot of text describing everything, instead I'll just show you how to use the plugin system. If you have any thoughts, comment the article or visit the discussion board at Codeplex.

The Plugin System

The plugin system consists of three parts.

The Application

The application creates an instance of the PluginManager which is used to find and load plugins. The plugins are found by specifying a search string which contains directory information and wild cards for the files. You can specify the security settings (Evidence) that each assembly should be loaded with, which is perfect if you have different access levels for your plugins.

Application Interfaces

The second assembly contains the interfaces that the application exposes towards the plugins. This assembly exists since you may not want to send your entire application to third party plugin developers.


And finally we got the actual plugin assemblies. Plugins can mark themselves dependent on other plugins. For instance, say that you have a newsletter plugin which generates and sends newsletters. The newsletter plugin needs an emailer which is specified in another plugin. The newsletter plugin can therefore mark itself as dependent on the emailer plugin, as a result of which the emailer will always be loaded before the newsletter plugin.

The Example

In this article, I'll demonstrate how to create a simple plugin.

First of all, we need to specify what the plugins should be able to do, and define which parts of the application are accessible from the plugins. All of this is added into a class library that will be sent to plugin developers.

Applications Shared Assembly

In this example, our application wants to let the plugins be able to register components and add menu items to the main application menu. By letting plugins register components, we got a quite flexible solution since plugins can use components registered by other plugins.

public interface IMyApplication : IApplication
    void AddMenuItem(string name, MenuItemClickedHandler clickHandler);
    void RegisterComponent<T>(T component) where T : class;
    T GetComponent<T>() where T : class;

public delegate void MenuItemClickedHandler(string name);

And the interface that plugins should implement:

public interface IMyPlugin : IPlugin
    void SayHelloTo(string name);

We don't have high expectations from the plugins, they are just required to say hello to anyone we tell them.

Plugin Interface

The plugin has a component that it will register, thus adding functionality to the application that can be used by the application itself or other plugins.

public interface IWorldPeace
    void Initiate();

The Plugin

The plugin contains two parts: First the class that implements the plugin interface, and then the class that implements IWordPeace that the plugin introduced.

public class MyPlugin : IMyPlugin
       private const string _pluginName = "MyPlugin";
       private readonly IPluginInfo _pluginInfo = new MyPluginInfo();
       private readonly IEnumerable<string> _dependencies = new List<string>();

       /// <span class="code-SummaryComment"><summary></span>
       /// This name is used to determine dependencies, should always be in English.
       /// Should not be confused with the human friendly name in
       /// <span class="code-SummaryComment"><see cref="IPlugin.PluginInfo"/>.</span>
       /// <span class="code-SummaryComment"></summary></span>
       public string PluginName
           get { return _pluginName; }

       /// <span class="code-SummaryComment"><summary></span>
       /// Information about the plugin.
       /// <span class="code-SummaryComment"></summary></span>
       public IPluginInfo PluginInfo
           get { return _pluginInfo; }

       /// <span class="code-SummaryComment"><summary></span>
       /// Other plugins that this one depends on.
       /// The list should contain <span class="code-SummaryComment"><see cref="PluginName"/>s.</span>
       /// <span class="code-SummaryComment"></summary></span>
       /// <span class="code-SummaryComment"><value>Is never null</value></span>
       public IEnumerable<string> Dependencies
           get { return _dependencies; }

       /// <span class="code-SummaryComment"><summary></span>
       /// Start the plugin
       /// <span class="code-SummaryComment"></summary></span>
       /// <span class="code-SummaryComment"><param name="application">Application interface exposed </span>
       /// towards the plugins.<span class="code-SummaryComment"></param></span>
       public void Start(IApplication application)
           IMyApplication myApplication = (IMyApplication) application;
           myApplication.RegisterComponent<IWorldPeace>(new WorldPeaceThroughLove());
           myApplication.AddMenuItem("Click me", OnClick);

       /// <span class="code-SummaryComment"><summary></span>
       /// Invoked when the user clicks on our menu item
       /// <span class="code-SummaryComment"></summary></span>
       /// <span class="code-SummaryComment"><param name="name"></param></span>
       private void OnClick(string name)
           Console.WriteLine("Omg! You clicked me!");

       /// <span class="code-SummaryComment"><summary></span>
       /// Function that must be implemented
       /// <span class="code-SummaryComment"></summary></span>
       /// <span class="code-SummaryComment"><param name="name"></param></span>
       public void SayHelloTo(string name)
           Console.WriteLine("Hello " + name);

And finally the world peace implementation:

public class WorldPeaceThroughLove : IWorldPeace
    public void Initiate()
        Console.WriteLine("Love is all around!");

The Application

We use a console application in this example, but it could be a Winforms or a Web application.

public class Program : IApplication
    private PluginManager<imyplugin> _pluginManager;
    private readonly IDictionary<type,> _components = new Dictionary<type,>();

    public static void Main()
        new Program().Start();

    public void AddMenuItem(string name, MenuItemClickedHandler clickHandler)
        // here we should add the menu item to a real application

    public void RegisterComponent>T<(T component) where T : class
        _components.Add(typeof(T), component);

    public T GetComponent>T<() where T : class
        return (T)_components[typeof(T)];

    private void Start()
        // Create a plugin manager and load it
        _pluginManager = new PluginManager<IMyPlugin>(this);

        // plugins are in the same folder as the application and 
        // their file names end with "Plugin.dll"
        _pluginManager.PluginPath = "*Plugin.dll"; 
        // Call a method defined in the plugin                       
        _pluginManager["MyPlugin"].SayHelloTo( "everyone!");

        // Access a registered component.
        IWorldPeace worldPeace = GetComponent<IWorldPeace><iworldpeace>();

Update: Unloading Plugins

I've got some questions about how to unload plugins. I have no support for this in the plugin system and I'll try to explain why.

First of all, there is no way to unload assemblies (DLLs) from an appdomain (application). Period.

Solution: Appdomains and Remoting

Although there's a way around it: using a secondary appdomain for all plugins, this means that the plugins are in something that can be considered as an external application (each appdomain has isolated memory and an unhandled exception in the secondary appdomain will not affect the primary appdomain) which means that you need to use remoting to be able to communicate between the plugins and the main application.

Having all plugins in the secondary appdomain means that you can't unload a single plugin, you have to unload all of them. But hey, you can use one appdomain for each plugin, right? Well sure; if you can live with the performance hit.

Another Problem

Let's say that you have a plugin which provides an addressbook with contacts to the rest of the application. Do you really want to unload it? Let's say that the application (or any of the other plugins) contain references to some of your contacts, what happens to them if you unload that plugin?

Unloading stuff is much more complex than you might think.

Final Words

That's it. Let me know if there's something that you did not understand.

Feel free to check my other projects: C# Webserver and TinyDAL.


  • 30th August, 2008: Initial post


This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


About the Author

Founder 1TCompany AB
Sweden Sweden

Comments and Discussions

QuestionLink not working Pin
Yug Kaswan20-Oct-18 22:47
memberYug Kaswan20-Oct-18 22:47 
GeneralMy vote of 5 Pin
Assil15-Jan-15 4:02
professionalAssil15-Jan-15 4:02 
Questionexample project Pin
Chris Anders17-Jan-14 7:04
memberChris Anders17-Jan-14 7:04 
AnswerRe: example project Pin
jgauffin17-Jan-14 7:58
memberjgauffin17-Jan-14 7:58 
GeneralRe: example project Pin
Chris Anders17-Jan-14 8:01
memberChris Anders17-Jan-14 8:01 
QuestionSyntax Question about the Source Code Pin
Sanjay Fisk15-Oct-09 9:17
memberSanjay Fisk15-Oct-09 9:17 
AnswerRe: Syntax Question about the Source Code Pin
jgauffin15-Oct-09 20:17
memberjgauffin15-Oct-09 20:17 
GeneralThanks Pin
André Baltazar5-Sep-09 2:34
memberAndré Baltazar5-Sep-09 2:34 
Generalhelp , newbe in cs (just installed VC++ 2005 pro evaluation version) [modified] Pin
some1One18-Sep-08 21:15
membersome1One18-Sep-08 21:15 
GeneralRe: help , newbe in cs (just installed VC++ 2005 pro evaluation version) Pin
jgauffin8-Sep-08 21:23
memberjgauffin8-Sep-08 21:23 
GeneralRe: done this , got exception. Pin
some1One18-Sep-08 22:10
membersome1One18-Sep-08 22:10 
GeneralRe: done this , got exception. Pin
jgauffin8-Sep-08 22:16
memberjgauffin8-Sep-08 22:16 
GeneralNot bad Pin
PIEBALDconsult3-Sep-08 10:51
protectorPIEBALDconsult3-Sep-08 10:51 
GeneralSystem.AddIn Pin
Szymon Pobiega3-Sep-08 10:11
memberSzymon Pobiega3-Sep-08 10:11 
GeneralRe: System.AddIn Pin
PIEBALDconsult3-Sep-08 11:01
protectorPIEBALDconsult3-Sep-08 11:01 
GeneralNot impressed Pin
dudeua2-Sep-08 22:13
memberdudeua2-Sep-08 22:13 
GeneralRe: Not impressed Pin
jgauffin2-Sep-08 22:26
memberjgauffin2-Sep-08 22:26 
GeneralPlugin and host communication Pin
JB-7-82-Sep-08 21:41
memberJB-7-82-Sep-08 21:41 
GeneralRe: Plugin and host communication Pin
jgauffin2-Sep-08 21:47
memberjgauffin2-Sep-08 21:47 
GeneralRe: Plugin and host communication Pin
JB-7-82-Sep-08 21:50
memberJB-7-82-Sep-08 21:50 
GeneralRe: Plugin and host communication Pin
jgauffin2-Sep-08 21:55
memberjgauffin2-Sep-08 21:55 
GeneralRe: Plugin and host communication Pin
JB-7-82-Sep-08 21:57
memberJB-7-82-Sep-08 21:57 
GeneralLittle Error on Build ... Pin
Jammer1-Sep-08 23:38
memberJammer1-Sep-08 23:38 
GeneralRe: Little Error on Build ... Pin
jgauffin1-Sep-08 23:49
memberjgauffin1-Sep-08 23:49 
GeneralRe: Little Error on Build ... Pin
Jammer2-Sep-08 7:27
memberJammer2-Sep-08 7:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Posted 29 Aug 2008


162 bookmarked