Plugin Architecture With Reflection

There was a time when I needed to create a configuration application on plugin architecture using reflection. It was a good experience that I want to share with you.

I had created this configuration application in Windows Form using reflection where I used a Windows Form having only one control (TabControl) and I was loading plugins (.dlls) in the blank application.

Below are the steps to create the Configuration App Solution.

Step 1

Create a blank solution with the name "ConfigurationManager Application".
 
Plugin Architecture with Reflection
 
Step 2

Add a Windows application project with the name "ConfigurationApplication" in the solution.

Plugin Architecture with Reflection
 
Step 3

Add a class library project called “CommonModule.Lib".

Plugin Architecture with Reflection
 
Step 4

Add a class library project called "ConnectDb.Lib".

Plugin Architecture with Reflection

Finally, the solution will look something like this.

Plugin Architecture with Reflection
 
Now, we will write some code but before that, we need to create 2 folders "Config" and "MenuPlugins" inside the Config folder. For my convenience, I have created this inside the debug directory of the bin folder and I am mapping it with the below line of code.
 
string menuPluginPath = Application.StartupPath + "\\Config\\MenuPlugins"
 
The Config folder contains "CustomPluginSequence.xml" which contains a sequence of plugins to load in the application. 
  1. <?xml version="1.0" encoding="utf-8" ?>         
  2. <Config>        
  3.   <Plugin key="SQLPlugin">DBConnect.LIB.dll</Plugin>  
  4. </Config>  
Now, we will add an interface called IMenuPluginService.cs in the project ConfigurationApp.COMMON and write the below properties and method.
  1. namespace ConfigurationApp.COMMON      
  2. {      
  3.     public interface IMenuPluginService      
  4.     {      
  5.         string PluginName { get; }      
  6.         TabPage ApplyMenuPlugin(TabPage tabMenuPlugin);      
  7.         UserControl UsrServiceControl { get; }      
  8.     }      
  9. }   

The next step is to add a UserControl called UserDBConnectControl where we are going to add the controls and the functionlty of the screen according to our usage. For my instance, I have created a SQL Server authentication screen. For reference, see the image below.

Plugin Architecture with Reflection

The next step is to add a class file called UserSQLControl.cs. In this class file, I have written the code to add the name of the Menu. Initialize the screen to the userControl and add the screen to the TabPage which will be loaded at run time by the TabControl which is there in the Configuration Application Windows project.

I have also implemented IMenuPluginService.cs interface to get all the properties and methods but before that, we need to provide the reference from ConfigurationApp.COMMON project to get the interface namespace. The code for this is written below.
  1.  using ConfigurationApp.COMMON;      
  2.  using System;      
  3.  using System.Collections.Generic;      
  4.  using System.Linq;      
  5.  using System.Text;      
  6.  using System.Threading.Tasks;      
  7.  using System.Windows.Forms;      
  8.        
  9.  namespace DBConnect.LIB      
  10. {      
  11.     public class UserSQLControl : IMenuPluginService      
  12.     {      
  13.         UserControl _userDatabaseControl;      
  14.         public string PluginName      
  15.         {      
  16.             get      
  17.             {      
  18.                 return "Connect SQL Server";      
  19.             }      
  20.         }      
  21.       
  22.         public UserControl UsrServiceControl      
  23.         {      
  24.             get      
  25.             {      
  26.                 if (_userDatabaseControl == null)      
  27.                 {      
  28.                     _userDatabaseControl = new UserDBConnectControl();      
  29.                 }      
  30.       
  31.                 return _userDatabaseControl;      
  32.             }      
  33.         }      
  34.       
  35.         public TabPage ApplyMenuPlugin(TabPage tabMenuPlugin)      
  36.         {      
  37.             tabMenuPlugin.Text = PluginName;      
  38.             tabMenuPlugin.Controls.Add(UsrServiceControl);      
  39.       
  40.             return tabMenuPlugin;      
  41.         }      
  42.     }      
  43. }      

Now, the next and final step is to add the code in ConfigurationForm.cs of ConfiruationManagerlibrary which is of a blank Windows Form.

Below is the code.

  1. using ConfigurationApp.COMMON;    
  2. using System;    
  3. using System.Collections.Generic;    
  4. using System.ComponentModel;    
  5. using System.Data;    
  6. using System.Drawing;    
  7. using System.IO;    
  8. using System.Linq;    
  9. using System.Reflection;    
  10. using System.Text;    
  11. using System.Threading.Tasks;    
  12. using System.Windows.Forms;    
  13. using System.Xml;    
  14.     
  15. namespace ConfigurationManager    
  16. {    
  17.     public partial class ConfigurationForm : Form    
  18.     {    
  19.         string menuPluginPath = Application.StartupPath + "\\Config\\MenuPlugins";    
  20.         string customSetMenuXML = Application.StartupPath + "\\Config\\CustomPluginSequence.xml";    
  21.     
  22.         IMenuPluginService IMPlugins;    
  23.     
  24.     
  25.         public ConfigurationForm()    
  26.         {    
  27.             InitializeComponent();    
  28.         }    
  29.     
  30.         private void ConfigurationForm_Load(object sender, EventArgs e)    
  31.         {    
  32.                
  33.             DirectoryInfo directoryInfo = new DirectoryInfo(menuPluginPath);    
  34.             XmlDocument document = new XmlDocument();    
  35.             document.Load(customSetMenuXML);    
  36.             XmlNodeList xmlNodeList = document.GetElementsByTagName("Plugin");      
  37.             int dllCount = xmlNodeList.Count;      
  38.             string[] files = new string[dllCount];  
  39.     
  40.             for (int i = 0; i < xmlNodeList.Count; i++)    
  41.             {    
  42.                 files[i] = menuPluginPath + "\\" + xmlNodeList[i].InnerText.ToString();    
  43.             }    
  44.   
  45.             foreach (string file in files)    
  46.             {    
  47.                 Assembly assembly = Assembly.LoadFrom(file);    
  48.     
  49.                 foreach (Type type in assembly.GetTypes())    
  50.                 {    
  51.                     if (type.GetInterfaces().Contains(typeof(IMenuPluginService)))    
  52.                     {    
  53.                         TabPage tabPage = new TabPage();    
  54.     
  55.                         IMPlugins = Activator.CreateInstance(type) as IMenuPluginService;    
  56.                         tabPage = IMPlugins.ApplyMenuPlugin(tabPage);    
  57.                         MenuTabs.Controls.Add(tabPage);    
  58.    
  59.                     }    
  60.                 }    
  61.     
  62.             }      
  63.         }    
  64.     }    
  65. }    

In the above code, I have used reflection to load the Plugin DLL as tab pages (However, here, for example, I have created only one Plugin DLL ) and added the tab pages in the Tab control of Windows form.

Note
As the plugin libraries could be built randomly, I have mapped the sequence from the sequence XML which I am getting by using the below line of code in the Form Load event.

  1. XmlDocument document = new XmlDocument();     
  2. document.Load(customSetMenuXML);      
  3. XmlNodeList xmlNodeList = document.GetElementsByTagName("Plugin");      
  4. int dllCount = xmlNodeList.Count;      
  5. string[] files = new string[dllCount];      
  6. for (int i = 0; i < xmlNodeList.Count; i++)    
  7. {    
  8.    files[i] = menuPluginPath + "\\" + xmlNodeList[i].InnerText.ToString();    
  9. }   

Next, I am looping from the correct sequence and from the reflection I am loading in the tab control.

I hope I was able to show you how to create a simple Windows application using the plugin architecture with reflection.

For reference, I am also attaching the code sample in this blog.

Note 2
I have not written the functionality of SQL screen as this is out of the scope of this example.