Saturday, January 22, 2005

C# Plugin In Architecture

Introduction
I have recently started developing an application for a client that allows them to manage various parts of the database that we built for them.

I am developing the system so that it is auto-updating and also completely plug-in based, in that the application is basically only a stub that loads the plugins.

I developed it this way for the obvious reason, that since the database and the requirements will be quite fluid, and changing all of the time, I wanted an easy way to roll out changes to them without compromising the original intent.

Interfaces
I developed the plugin system using a base of interfaces to define the contract between the plugins and the host application. In this manner, we can create a concrete definition of what the application expects from the plug in, and what the plug in can expect from the application.

1. IPlugin

namespace NPIMSPI
{
///


/// Summary description for IPlugin.
///

public interface IPlugin
{
void Initialize(IPluginHost host);
string Name
{
get;
set;
}
PluginTypes Type
{
get;
set;
}

IPluginHost Host
{
get;
set;
}

string Author
{
get;
set;
}

string Version
{
get;
set;
}

void Show();

System.Windows.Forms.UserControl MainInterface
{
get;
set;
}
}
}

This interface defines the base interface from which all plugins will inherit. You can see that it provides a method for Initializing the plugin (Initialize()), a method to Show the plugin (Show()), and 6 get/set definitions for various properties.

One notable get/set definition is the MainInterface definition. This is the get/set method that will tell the host application what component to add to the plugin container (in this case a tab control). More on that later.

2. IPluginHost


public interface IPluginHost
{
void Register(IPlugin Plugin);
void SwitchMenu(System.Windows.Forms.MainMenu Menu);
string Request(string Method,NameValueCollection Arguments);
string Request(string Method,string Argument);
string Request(string Method,string Argument,bool CloseOnComplete);
string Request(string Method,NameValueCollection Arguments,bool CloseOnComplete);
void Stop();
void Stop(string Message);
PluginCollection AvailablePlugins
{
get;
set;
}
void CloseWebServiceForm();
}


This interface is inherited by the host application. It defines the methods and properties accessible by the plugins. The request methods are there since the plugins communicate through that application to a web service which provides XML results to queries by the plugins. Again, we'll cover this a bit more later.

Enum - PluginTypes
This enum is simply allows for the plugin to tell the host application what type it is. This is used for when the host application registers the plugin. There are three types at this time; Menuitem, Tabitem, ButtonItem.


namespace NPIMSPI
{
///
/// Summary description for EnumPluginTypes.
///

public enum PluginTypes
{
Menuitem,
Tabitem,
ButtonItem
}
}

PluginBase
I decided that since most plugins will require much of the same functionality, that I would build a base class from which plugins would inherit. Appropriately named, PluginBase.
namespace NPIMSPI
{
///
/// Summary description for PluginBase.
///

public class PluginBase : IPlugin
{
#region Private Members
string name;
PluginTypes type;
System.Windows.Forms.UserControl mainInterface;
IPluginHost host;
string version="0.0.0.0";
string author = "undefined";
#endregion
public PluginBase()
{
//
// TODO: Add constructor logic here
//
}
#region IPlugin Members
public virtual void Initialize(IPluginHost host)
{
Console.WriteLine("Init "+this.GetType().ToString());
this.host = host;
}
public string Name
{
get
{
// TODO: Add PluginBase.Name getter implementation
return this.name;
}
set
{
this.name = value;
}
}
public NPIMSPI.PluginTypes Type
{
get
{
// TODO: Add PluginBase.Type getter implementation
return this.type;
}
set
{
this.type = value;
}
}
public virtual void Show()
{
this.Show();
}

public IPluginHost Host
{
get
{
return this.host;
}
set
{
this.host = value;
}
}

public string Author
{
get
{
return this.author;
}
set
{
this.author = value;
}
}
public string Version
{
get
{
return this.version;
}
set
{
this.version = value;
}
}
public System.Windows.Forms.UserControl MainInterface
{
get
{
return this.mainInterface;
}
set
{
this.mainInterface = value;
}
}
#endregion
}
}


The PluginBase is the base class for most plugins, and as you can see inherits from IPlugin. I've implemented the IPlugin members, and created private members to store the information. I've also left the Show(), and Initialize(IPluginHost host); members virtual so that they may easily be overridden.

method Initialize(IPluginHost host)
This method is called as the host application loads the plugin. It passes a IPlugin host to the plugin, so that 2 way communication can be implemented.