Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / programming / threads

Plugged.NET - An event based plug-in library for enterprise application integration and extensibility

4.89/5 (19 votes)
25 Jul 2013CPOL6 min read 35K   1.4K  
An event based plug-in library for enterprise application integration, extensibility and cross business application management.

Introduction 

Why do we need a plugin framework? 

The need of time has pointed developers towards rapid component development and plug-n-play architectures. The industry is looking towards enterprise product portfolio integration and/or some form of ESBs. I have heard several talks from industrial king-pins trying to prove apples as oranges (or at least a new red color hard cousin of orange which can internally look and feel just like orange but gives so much more benefit). Such thoughts, I agree, can either come from someone under severe constipation or from look-I-am-Einstein brains. But the arguments are also not entirely false. For product survival it has becomes very important to be adaptive, extensible and polymorphic in as many places as possible. This is so much more true in case of small-to-mid size organizations targeting small-to-mid-size market. 

Another very interesting business need is compartmentalizing multiple business logic processes, across physically diverse development groups and then integrate them in the same assembly line. Even in such context using a plugin mode of separation becomes important.

Background

I've suffered (working) for several months in 'enterprise application-portfolio integration platforms' where everyone expects a plugin to be no less than Albus Dumbledore, I have learnt, rather in a hard way, to propose using a plugin management platform uniformly across multiple integratable applications. There is rather no compulsion to use it at the beginning, but as soon as you think of a plugin architecture, think of uniforming them. 

This article is targeted at such requirements where it can give a quick start towards plugin hosting, management and integration. By using such a framework, as a developer, you are only writing your custom BL and not bother to dirty your hand.

How does it work?

Event based plugin interaction/invocation

Times have changed. Now a plugin is expected to be no less than a superhuman.

  • It needs to understand host application gestures 
  • It needs to work in the background (async) 
  • It needs to raise and subscribe to platform defined events 
  • It needs to change when a newer version needs to be deployed 
  • It needs to integrate with host of other invocation channels 

So the article proposes the plugin to be event based. The plugin handshakes with the host platform during initialization. And such a handshake is composed of a mutual two-way subscription to the interesting events. This handshake would live until the plugin is living in the host scope/lifetime. Some initialization is still a simple invocation but these, in principle, could also be graduated to events. My personal take is, an event based communication is only necessary when its occurrence (or its time frame) is uncertain. Actions such as initialization is generally obvious and can be spared from the overhead from an event based invocation.

As Spiderman said, "With power comes responsibility", I am too small an entity to prove it wrong. So here comes your responsibilities starting with using Dispatcher object when you use this (which mostly will be the case) in an UI intensive application(s).

Managed Extensibility Framework (MEF)

A bit of a cakewalk and hand-washing from the good old days' "dirty work". A good or great part of hosting plugins is to load them. A few years back developers had to jump, catch and yell (in short a circus effort) to reflectionalize object creation. And then there was MEF (http://mef.codeplex.com/). In short it helped to quickly and dynamically wrap the plugin instance creating pain. With several other nifty utilities here this one proved quite a blessing. Our PluginManager internally uses a factory here which serves as the heart of the entire system and the heart's first beat looks like this:

C#
public void Compose()
{
    var catalog = new AggregateCatalog();
    catalog.Catalogs.Add(new DirectoryCatalog(extensionsPath));
    Directory.GetDirectories(extensionsPath).ToList().ForEach(
      p => catalog.Catalogs.Add(new DirectoryCatalog(p)));

    container = new CompositionContainer(catalog);
    container.ComposeParts(this);
} 

There are many things which comes free, one of the main ones is automatic dependency resolving from multiple disjoint probing paths.

The class is hidden behind a short interface (in case/if/when there is a day when MEF is runs obsolete). 

C++
public interface IComposition<T>
{
    void Compose();
    void Decompose();

    IEnumerable<T> ComposedItems { get; set; }
} 

With these serving as the boiler plate code the rest of the hosting code kicks off... 

The Plugin Host

The term host is a little blown up here, may be a container would sound more appropriate. But again this does more than container. These few classes are responsible for:

  • Load plugin assemblies (it can be configured 'from where' - I have used the users %APPDATA% folder)
  • Serves as a one stop shop from standard application to plugin queries

A sample WPF window is also added to demonstrate the primary usage of the Plugin-Platform. Please note that the sampleHost only does the bare minimum to load plugins. There are several other features to be explored (documented below).

Here are the two most important methods of the host: 

C#
private bool RegisterPluginHandshake(IEnumerable<PluginInfo> plugins)
{
    return pluginMgr.RegisterExtensions(this, 
             PluginNotifyMessage, GetUserContext(), plugins);
}

private void UnRegisterPluginHandshake(IEnumerable<PluginInfo> plugins)
{
    pluginMgr.UnLoadExtensions(this, PluginNotifyMessage, plugins);
} 

A little deeper into the Plugin Platform... 

Here is a functional diagram of the scope of the platform. The mentioned interface names might differ in attached code. But it should be easy to determine which are the ones. Below is the interface that manages the event contract.

Image 1

C#
public interface IApplicationEvents
{
   // called when popup Application starts
   event EventHandler OnApplicationStart;

   // called when popup Application is closed
   event EventHandler OnApplicationClose;

   // called when the module is first time loaded
   event EventHandler OnModuleInitalize;

   // called when any module file action 
   event EventHandler OnFileSystemEvent;

   // called when any module action like show window
   event EventHandler OnActivateEvent;      

}

public interface IExtensionEvents
{
    event EventHandler OnStarted;
    event EventHandler OnCompleted;
    event EventHandler OnError;
} 

It is important to note here that the application and the plugins both are event sources themselves. While the platform is free to decide what kind of a event it wants to be part of the domain, the plugins are limited to raise only those events that the platform has pre-decided to be listened by itself. This in no way should be understood as a heavy-handed decision or a medium to control. There could be a host of interesting events and all of them could be made available under multiple versions/releases. Please check the illustration below.

574189/PluggedImage2.PNG

Using the code

The code in the framework is straight-forward and it is possible to just work with Common.plugin.Platform.dll (unless you need to change the framework or debug). Two basic plugins are included in the solution to get you started. 

  • KickStartPlugin - As stupid as the name could be it just listens to the right click context menu item event from Windows Explorer and responds with another parallel event. This happens through the singleton application instance (the code for which is included but beyond the scope of discussion in context with plugin integration)
  • TimeEventPlugin - Another equally stupid use-case. This plugin internally uses a timer to raise events every 10 seconds to bog the application out (just for your interest).

Below is a normal screenshot of the application. 

574189/PluggedImage3.PNG

Points of Interest

To summarize the framework (or the idea) is targeted at 

  • to publish your application and let independent software/teams create custom functionality to extend your application externally
  • integrating multiple business processes in the same assembly line (if need be).
  • manage complex development functions but segregating efforts and then merging the application under a container 

Future 

  • COM integration for third party COM app.
  • Implicit authentication with logged-in or ActiveDirectory user.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)