Dynamic Load Assembly

Introduction 

 

Dynamic library loading is nothing new in native C++. In Microsoft Window’s implementation, this capability is realized with the use of Dynamic Link Library (DLL). This feature greatly expands the flexibility of an application where new features can be added / modified in the form of plug-in without the need to recompile the entire application. Similar capability is provided in .NET framework to dynamically load assemblies which make plug-in development for .NET based application possible. Moreover, dynamic assembly loading that .NET framework provides is much more powerful than native C++ DLL.

Wikipedia: plug-in is a software component that adds a specific feature to an existing software application. 

Download Demo
Download Sample Project




Overview


Dynamic loading is only possible only when application and component are talking the same language. In such, both application and plug-in component need to communicate with each other using an agreed interface. The content of this interface cannot be changed for the entire lifetime, modifying the content of this interface required the application and all the components to be completely recompiled. See image below: 



Implementation

 

An example of dynamic assembly loading projects is created as shown below for further discussion. This example is coded in C# using Visual Studio 2010 where both the application and plug-in assemblies are referenced to PluginInterface.dll.


The demo application contains 2 parts: Simple Test and Advance Test where Simple Test will load from a defined assembly whereas Advance Test will discover and load selected assemblies in the Plugins folder. Besides, a build configuration named “NewPlugin” is created to simulate plug-in development where new plug-in is created without recompiling the main application.

IPlugin Interface

 

The IPlugin interface is no different from any ordinary interface. It may contain property, methods (function) and events. Since the main application has no visibility of the classes implemented in plug-in assemblies, IPlugin is the only access between application and plug-in assemblies.
public interface IPlugin
{
    string Name {get; }
    string GetDescription();
        
    double GetLastResult { get; }
    double Execute(double value1, double value2);

    event EventHandler OnExecute;

    void ExceptionTest(string input);
} 

 

Load Assembly 

 

As you can see, plug-in assemblies are not referenced by the main application except PluginInterface. Assembly loading is done by using LoadAssembly in System.Reflection namespace. In this example, we assume that each plug-in assembly contains only one class that implements the IPlugin interface. Theoretically, it is possible to have more than one class in an assembly which implement the IPlugin interface, we leave it for you to explore further.
private PluginInterface.IPlugin LoadAssembly(string assemblyPath)
{
    string assembly = Path.GetFullPath(assemblyPath);
    Assembly ptrAssembly = Assembly.LoadFile(assembly);
    foreach (Type item in ptrAssembly.GetTypes())
    {
        if (!item.IsClass) continue;
        if (item.GetInterfaces().Contains(typeof(PluginInterface.IPlugin)))
        {
            return (PluginInterface.IPlugin)Activator.CreateInstance(item);
        }
    }
    throw new Exception("Invalid DLL, Interface not found!");
} 
Once the assembly is successfully loaded into the application, it can be used just like a normal class instance regardless of whether it is a function call or an event subscription. An example of event subscription on loaded assemblies is shown as below:
currPlugin = LoadAssembly(".\\Plugins\\" + cbAssemblies.Text + ".dll");
//Subscribe Event.
 currPlugin.OnExecute += new EventHandler(currPlugin_OnExecute); 

Limitation

 

Despite its high flexibility, there is one limitation in dynamic assemblies loading where there is no way to unload the loaded assemblies until the main application is terminated, even with the System.AppDomain will not release the loaded assembly after AppDomain.Unload is called.

 

Exception Handling 

 

Exceptions can traverse from loaded assemblies to main application without much problem. The same try ... catch block is sufficient to handle exception raised from assembly unlike native C++ DLL where errors are normally returned as error codes and error messages.

Popular posts from this blog

C# DSP Simulation - DSP Lab

C# DSP Toolbox: Digital Filters (Updated)