Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Dynamic Load .NET Assembly

0.00/5 (No votes)
10 Oct 2013 1  
Example implementation of dynamic assembly loading in C#

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.

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.

  • DynamicLoadAssembly: An application created to test dynamic load capability in .NET framework
  • PluginInterface: Bridge that link between application and plug-in assemblies
  • Plugin_Sum, Plugin_Multiplier, Plugin_Calculation: Plug-in assemblies which implement IPlugin interface in 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");
currPlugin.OnExecute += new EventHandler(currPlugin_OnExecute); //Subscribe Event. 

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.

History

  • 10-Oct-2013: Initial release (Version 1.0.0)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here