Introduction
One day my friend told me he needed to change his way of releasing builds. It meant he had to fix a batch to compile and publish several products. Such a process can be tedious since it has to be very reliable and you have to remember all the required DOS commands. Each step of a batch is in fact a command that can be accomplished in pure DOS or executing external executable files. So I thought it would be cool to make a batch editor in the following way:
- Choose a command from a toolbox
- Support re-ordering
- Save it to disk for further use
- Visualize all commands in a simple way
- Enable adding custom tools as plug-ins
- Test the batch before it goes somewhere (Scheduled Tasks) with optimizations
Obviously, I had an application in mind that had a toolbox to drop the commands on a batch document form. Something with an Outlook Look and Feel (OLAF). This way, we could easily edit/move up, down/delete the items. What if someone needs to use a custom command in his batch process?
Let's say, my friend needed to Compile (with a .NET compiler) and publish his work to several directories. It implied Restarting some IIS service and backing-up the old version before anything. Sending an email to his team to tell them to take the coffee break while he is uploading a new version. They would get an alert after the version was successfully uploaded and passed an automated crash test. All these steps in the process could be broken to atomic operations like: Compile, Backup, Restart Services, Copy, Send Email, etc � but it seems that limiting the toolbox to our development would be a mistake since each one of us needs some other operations. I decided to build the toolbox in a way that developers would add their own tools. The plug-in mechanism. Since I love programming in .NET (C#), I started to code my platform for plugging using reflection.
Background
The article describes a simple way of creating a flexible application, following the architecture below:
Figure 1: The plug-in model
Figure 2: The plug-in into work
The Contract
The platform doesn't know the plug-in collection itself. But it surely knows the interface BBuilder.Interface
. On load the application loads all the assemblies that implement BBuilder.Interface
.
The "Contract" is divided by two parts:
- The visual contract � A UserControl (ActionPanelControl) that defines all the defaults and UI validations
- The functional contract � An interface (IActionPanel) that defines the real logic of the plug-in: The way it generates the command line.
Is Reflection "Black Magic"?
A factory is used to provide an instance of the desired assembly; it uses reflection.
public IActionPanel GetInstanceOfPlugin(string type,string assemblyPath)
{
if (!dictPlugins.ContainsKey(type))
{
dictPlugins.Add(type, LoadPluginAssembly(assemblyPath));
}
return Activator.CreateInstance(
dictPlugins[type].GetType(type)) as IActionPanel;
}
Using the Code
This tutorial should allow you to add a new plug-in named "Search" within a few steps:
- Make a new project as "Class Library", name it "BBuilder.Plugins.Search"
- Add a new item as user control
- Name it for example, "Search.cs"
- Add a new item as resource file
- Rename it "Resource.resx"
- Double click on "Resource.resx". Add an Image resource named "Search".
- Click on the Search image and go to Properties (F4)
- Change persistence to 'Embedded in .resx', then Save and Close.
- Add a reference to BBuilder.Interface DLL
- In Search.cs � Change to the following lines:
using BBuilder.Interface;
namespace BBuilder.Plugins.Search
{
public partial class Search : ActionPanelControl,IActionPanel
{
public Search()
{
InitializeComponent();
}
#region IActionPanel Members
public string Category
{
get { return "BBuilder"; }
}
public string AuthorName
{
get { return "Breeback\nDownload updates at" +
"http://www.breezback.com."; }
}
public string ImageKey
{
get { return "Search"; }
}
public string ActionName
{
get { return "Search Files and Folders"; }
}
public string Description
{
get { return "search for files and folders"; }
}
public string CommandLine
{
get { return "echo my commandline goes here"; }
}
public System.Drawing.Bitmap Image
{
get
{
return Resource.Search;
}
}
public string Serialize()
{
return "";
}
public void Deserialize(string strPanel)
{
}
#endregion
}
}
- Compile the Project
- Copy "BBuilder.Plugins.Search.dll" to "C:\Program Files\Breezback\BBuilder\Plugins"
Points of Interest
- Reflection for a flexible application
- Factory and Singleton design patterns
- IComparer implementation to generate a custom order
- Creating a windows application in .NET with a professional look like Outlook. With a powerful grid that overrides the Rendering
- Spawn process for Shell : Redirecting input/output
- Make a responsive UI with Background worker
- Deploying the application with a Setup project, with custom file type and icons
History
08-16-2003:
Credits
I'd like to thank all the people who helped me in this project, even if unconsciously:
- OLAF Project� For the exceptional grid
- Noogen Project for the Validators
- Gregory Young for his expertise
- Dina for her patience